Bug 92900 - Cannot use member of packed struct in constexpr
Summary: Cannot use member of packed struct in constexpr
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 9.2.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks: constexpr
  Show dependency treegraph
 
Reported: 2019-12-10 21:14 UTC by Anton Dmitrovsky
Modified: 2020-11-09 01:54 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Anton Dmitrovsky 2019-12-10 21:14:48 UTC
Following program generates an error for a struct packed with __attribute__((packed)) but not with #pragma pack(1)

Compiled as 
g++ -O2 -std=c++17 -Wall -Wextra -Wpedantic -Wstrict-aliasing -fstrict-aliasing

Error: the value of 's2' is not usable in a constant expression
   27 |     constexpr auto sz2 = std::size(s2.i);

Web compiler:
https://godbolt.org/z/h-7i4p


#include <iterator>

#pragma pack(1)
struct S1
{
    int i[10];
}
;
#pragma pack()

struct S2
{
    int i[10];
}
__attribute__((packed)) // comment this to make it compile
;

#define LEN(a) (sizeof(a) / sizeof(a[0]));

void f()
{
    S1 s1{};
    constexpr auto sz1 = std::size(s1.i);
    (void)sz1;

    S2 s2{};
    constexpr auto sz2 = std::size(s2.i);
    (void)sz2;

    constexpr auto sz3 = LEN(s2.i);
    (void)sz3;
}
Comment 1 Eric Gallager 2019-12-10 23:52:24 UTC
possibly related to bug 60972
Comment 2 Jakub Jelinek 2019-12-11 17:53:33 UTC
Testcase without includes:
typedef __SIZE_TYPE__ size_t;
template <typename T, size_t N>
constexpr size_t size (const T (&)[N]) noexcept { return N; }
#pragma pack(1)
struct S1 { int i[10]; };
#pragma pack()
struct __attribute__((packed)) S2 { int i[10]; };
#define LEN(a) (sizeof(a) / sizeof(a[0]));

size_t
foo ()
{
  S1 s1{};
  constexpr auto sz1 = size (s1.i);
  S2 s2{};
  constexpr auto sz2 = size (s2.i);
  constexpr auto sz3 = LEN(s2.i);
  return sz1 + sz2 + sz3;
}
Comment 3 Jakub Jelinek 2019-12-11 18:41:36 UTC
The difference between those two is that s1.i FIELD_DECL doesn't have DECL_PACKED set on it (a bug in the #pragma pack support?), while with packed attribute it does.
DECL_PACKED on the FIELD_DECL in s2 is set during check_field_decls called from check_bases_and_members from finish_struct*.
For S1, TYPE_PACKED is actually never set, and thus DECL_PACKED neither.
The reason the s2 case is rejected is that lvalue_kind returns something with clk_packed on it, forcing a temporary.  That was added in
https://gcc.gnu.org/ml/gcc-patches/2003-07/msg01664.html
CCing the author.
Note, even in the C FE pragma pack actually doesn't cause TYPE_PACKED/DECL_PACKED to be set, it isn't really identical to what packed attribute does either, e.g. I believe we should only set DECL_PACKED on FIELD_DECLs where packed attribute on the containing type or pragma pack or -fpack-struct= etc. actually lowered the alignment over what it would normally have.
Comment 4 Jonathan Wakely 2019-12-11 20:09:20 UTC
Since accessing a misaligned variable is undefined behaviour, I don't think it should be permitted in constant expressions (at least for the cases where the alignment is reduced from its natural value).