Hi! The following testcases (one with #embed, one with large initializer turned into RAW_DATA_CST) show that I forgot to handle RAW_DATA_CST in module streaming.
Similar to the PCH case we need to stream out RAW_DATA_CST with NULL RAW_DATA_OWNER (i.e. a tree which has data owned by libcpp buffer) so that it will be streamed back in as STRING_CST which owns the data, but because the data can be really large (hopefully not so much for header modules though), without actually trying to build a STRING_CST on the module writing side because that would mean another large allocation and copying of the large data. RAW_DATA_CST with RAW_DATA_OWNER then needs to be streamed out and in by streaming the owner and offset from owner's data and length. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2025-03-04 Jakub Jelinek <ja...@redhat.com> PR c++/119076 * module.cc (trees_out::start): Handle RAW_DATA_CST. (trees_in::start): Likewise. (trees_out::core_vals): Likewise. (trees_in::core_vals): Likewise. * g++.dg/modules/pr119076-1_a.H: New test. * g++.dg/modules/pr119076-1_b.C: New test. * g++.dg/modules/pr119076-2_a.H: New test. * g++.dg/modules/pr119076-2_b.C: New test. --- gcc/cp/module.cc.jj 2025-01-28 09:23:38.195599960 +0100 +++ gcc/cp/module.cc 2025-03-04 00:52:50.947063367 +0100 @@ -5319,6 +5319,30 @@ trees_out::start (tree t, bool code_stre str (TREE_STRING_POINTER (t), TREE_STRING_LENGTH (t)); break; + case RAW_DATA_CST: + if (RAW_DATA_OWNER (t) == NULL_TREE) + { + /* Stream RAW_DATA_CST with no owner (i.e. data pointing + into libcpp buffers) as something we can stream in as + STRING_CST which owns the data. */ + u (0); + /* Can't use str (RAW_DATA_POINTER (t), RAW_DATA_LENGTH (t)); + here as there isn't a null termination after it. */ + z (RAW_DATA_LENGTH (t)); + if (RAW_DATA_LENGTH (t)) + if (void *ptr = buf (RAW_DATA_LENGTH (t) + 1)) + { + memcpy (ptr, RAW_DATA_POINTER (t), RAW_DATA_LENGTH (t)); + ((char *) ptr)[RAW_DATA_LENGTH (t)] = '\0'; + } + } + else + { + gcc_assert (RAW_DATA_LENGTH (t)); + u (RAW_DATA_LENGTH (t)); + } + break; + case VECTOR_CST: u (VECTOR_CST_LOG2_NPATTERNS (t)); u (VECTOR_CST_NELTS_PER_PATTERN (t)); @@ -5400,6 +5424,24 @@ trees_in::start (unsigned code) } break; + case RAW_DATA_CST: + { + size_t l = u (); + if (l == 0) + { + /* Stream in RAW_DATA_CST with no owner as STRING_CST + which owns the data. */ + const char *chars = str (&l); + t = build_string (l, chars); + } + else + { + t = make_node (RAW_DATA_CST); + RAW_DATA_LENGTH (t) = l; + } + } + break; + case VECTOR_CST: { unsigned log2_npats = u (); @@ -6311,6 +6353,22 @@ trees_out::core_vals (tree t) /* Streamed during start. */ break; + case RAW_DATA_CST: + if (RAW_DATA_OWNER (t) == NULL_TREE) + break; /* Streamed as STRING_CST during start. */ + WT (RAW_DATA_OWNER (t)); + if (streaming_p ()) + { + if (TREE_CODE (RAW_DATA_OWNER (t)) == RAW_DATA_CST) + z (RAW_DATA_POINTER (t) - RAW_DATA_POINTER (RAW_DATA_OWNER (t))); + else if (TREE_CODE (RAW_DATA_OWNER (t)) == STRING_CST) + z (RAW_DATA_POINTER (t) + - TREE_STRING_POINTER (RAW_DATA_OWNER (t))); + else + gcc_unreachable (); + } + break; + case VECTOR_CST: for (unsigned ix = vector_cst_encoded_nelts (t); ix--;) WT (VECTOR_CST_ENCODED_ELT (t, ix)); @@ -6845,6 +6903,13 @@ trees_in::core_vals (tree t) /* Streamed during start. */ break; + case RAW_DATA_CST: + RT (RAW_DATA_OWNER (t)); + gcc_assert (TREE_CODE (RAW_DATA_OWNER (t)) == STRING_CST + && TREE_STRING_LENGTH (RAW_DATA_OWNER (t))); + RAW_DATA_POINTER (t) = TREE_STRING_POINTER (RAW_DATA_OWNER (t)) + z (); + break; + case VECTOR_CST: for (unsigned ix = vector_cst_encoded_nelts (t); ix--;) RT (VECTOR_CST_ENCODED_ELT (t, ix)); --- gcc/testsuite/g++.dg/modules/pr119076-1_a.H.jj 2025-03-03 10:22:17.514294281 +0100 +++ gcc/testsuite/g++.dg/modules/pr119076-1_a.H 2025-03-03 12:04:10.041822216 +0100 @@ -0,0 +1,41 @@ +// { dg-additional-options "-fmodule-header -Wno-pedantic" } +// { dg-module-cmi {} } + +constexpr unsigned char a[] = { +#embed __FILE__ +}; + +constexpr int +foo (const unsigned char *p, int s) +{ + int r = 0; + for (int i = 0; i < s; ++i) + r += p[i]; + return r; +} + +constexpr int b = foo (a, sizeof a); + +inline int +bar () +{ + const unsigned char b[] = { + #embed __FILE__ + }; + int r = 0; + for (int i = 0; i < sizeof b; ++i) + r += b[i]; + return r; +} + +inline int +baz () +{ + const long int c[] = { + #embed __FILE__ + }; + int r = 0; + for (int i = 0; i < sizeof (c) / sizeof (c[0]); ++i) + r += c[i]; + return r; +} --- gcc/testsuite/g++.dg/modules/pr119076-1_b.C.jj 2025-03-03 10:22:21.241242404 +0100 +++ gcc/testsuite/g++.dg/modules/pr119076-1_b.C 2025-03-03 12:00:43.439674082 +0100 @@ -0,0 +1,12 @@ +// PR c++/119076 +// { dg-do run } +// { dg-additional-options "-fmodules-ts" } + +import "pr119076-1_a.H"; + +int +main () +{ + if (bar () != b || baz () != b) + __builtin_abort (); +} --- gcc/testsuite/g++.dg/modules/pr119076-2_a.H.jj 2025-03-03 12:02:12.254448113 +0100 +++ gcc/testsuite/g++.dg/modules/pr119076-2_a.H 2025-03-03 12:03:19.239523473 +0100 @@ -0,0 +1,65 @@ +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } + +constexpr unsigned char a[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, +}; + +constexpr int +foo (const unsigned char *p, int s) +{ + int r = 0; + for (int i = 0; i < s; ++i) + r += p[i]; + return r; +} + +constexpr int b = foo (a, sizeof a); + +inline int +bar () +{ + const unsigned char b[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + }; + int r = 0; + for (int i = 0; i < sizeof b; ++i) + r += b[i]; + return r; +} + +inline int +baz () +{ + const long int c[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + }; + int r = 0; + for (int i = 0; i < sizeof (c) / sizeof (c[0]); ++i) + r += c[i]; + return r; +} --- gcc/testsuite/g++.dg/modules/pr119076-2_b.C.jj 2025-03-03 12:03:31.627352476 +0100 +++ gcc/testsuite/g++.dg/modules/pr119076-2_b.C 2025-03-03 12:03:40.061236054 +0100 @@ -0,0 +1,12 @@ +// PR c++/119076 +// { dg-do run } +// { dg-additional-options "-fmodules-ts" } + +import "pr119076-2_a.H"; + +int +main () +{ + if (bar () != b || baz () != b) + __builtin_abort (); +} Jakub