Note that the @code{length} option is only meant for use with arrays of
non-atomic objects, that is, objects that contain pointers pointing to
other GTY-managed objects. For other GC-allocated arrays and strings
-you should use @code{atomic}.
+you should use @code{atomic} or @code{string_length}.
+
+@findex string_length
+@item string_length ("@var{expression}")
+
+In order to simplify production of PCH, a structure member that is a plain
+array of bytes (an optionally @code{const} and/or @code{unsigned} @code{char
+*}) is treated specially by the infrastructure. Even if such an array has not
+been allocated in GC-controlled memory, it will still be written properly into
+a PCH. The machinery responsible for this needs to know the length of the
+data; by default, the length is determined by calling @code{strlen} on the
+pointer. The @code{string_length} option specifies an alternate way to
+determine the length, such as by inspecting another struct member:
+
+@smallexample
+struct GTY(()) non_terminated_string @{
+ size_t sz;
+ const char * GTY((string_length ("%h.sz"))) data;
+@};
+@end smallexample
@findex skip
@item skip
enum write_types_kinds kind;
};
-static void output_escaped_param (struct walk_type_data *d,
+static void output_escaped_param (const struct walk_type_data *d,
const char *, const char *);
static void output_mangled_typename (outf_p, const_type_p);
static void walk_type (type_p t, struct walk_type_data *d);
print error messages. */
static void
-output_escaped_param (struct walk_type_data *d, const char *param,
+output_escaped_param (const struct walk_type_data *d, const char *param,
const char *oname)
{
const char *p;
get_string_option (options_p opt, const char *key)
{
for (; opt; opt = opt->next)
- if (strcmp (opt->name, key) == 0)
+ if (opt->kind == OPTION_STRING && strcmp (opt->name, key) == 0)
return opt->info.string;
return NULL;
}
;
else if (strcmp (oo->name, "callback") == 0)
;
+ else if (strcmp (oo->name, "string_length") == 0)
+ ;
else
error_at_line (d->line, "unknown option `%s'\n", oo->name);
{
oprintf (d->of, "%*sgt_%s_", d->indent, "", wtd->prefix);
output_mangled_typename (d->of, f);
- oprintf (d->of, " (%s%s);\n", cast, d->val);
+
+ /* Check if we need to call the special pch note version
+ for strings that takes an explicit length. */
+ const auto length_override
+ = (f->kind == TYPE_STRING && !strcmp (wtd->prefix, "pch_n")
+ ? get_string_option (d->opt, "string_length")
+ : nullptr);
+ if (length_override)
+ {
+ oprintf (d->of, "2 (%s%s, ", cast, d->val);
+ output_escaped_param (d, length_override, "string_length");
+ }
+ else
+ oprintf (d->of, " (%s%s", cast, d->val);
+
+ oprintf (d->of, ");\n");
if (d->reorder_fn && wtd->reorder_note_routine)
oprintf (d->of, "%*s%s (%s%s, %s%s, %s);\n", d->indent, "",
wtd->reorder_note_routine, cast, d->val, cast, d->val,
int
gt_pch_note_object (void *obj, void *note_ptr_cookie,
- gt_note_pointers note_ptr_fn)
+ gt_note_pointers note_ptr_fn,
+ size_t length_override)
{
struct ptr_data **slot;
(*slot)->obj = obj;
(*slot)->note_ptr_fn = note_ptr_fn;
(*slot)->note_ptr_cookie = note_ptr_cookie;
- if (note_ptr_fn == gt_pch_p_S)
+ if (length_override != (size_t)-1)
+ (*slot)->size = length_override;
+ else if (note_ptr_fn == gt_pch_p_S)
(*slot)->size = strlen ((const char *)obj) + 1;
else
(*slot)->size = ggc_get_size (obj);
void *);
/* Used by the gt_pch_n_* routines. Register an object in the hash table. */
-extern int gt_pch_note_object (void *, void *, gt_note_pointers);
+extern int gt_pch_note_object (void *, void *, gt_note_pointers,
+ size_t length_override = (size_t)-1);
/* Used by the gt_pch_p_* routines. Register address of a callback
pointer. */
/* PCH and GGC handling for strings, mostly trivial. */
extern void gt_pch_n_S (const void *);
+extern void gt_pch_n_S2 (const void *, size_t);
extern void gt_ggc_m_S (const void *);
/* End of GTY machinery API. */
>_pch_p_S);
}
+void
+gt_pch_n_S2 (const void *x, size_t string_len)
+{
+ gt_pch_note_object (CONST_CAST (void *, x), CONST_CAST (void *, x),
+ >_pch_p_S, string_len);
+}
+
/* User-callable entry point for marking string X. */
--- /dev/null
+// { dg-do compile { target c++11 } }
+#include "pch-string-nulls.H"
+static_assert (X[4] == '[' && X[5] == '!' && X[6] == ']', "error");
/* Payload of a NUMBER, STRING, CHAR or COMMENT token. */
struct GTY(()) cpp_string {
unsigned int len;
- const unsigned char *text;
+
+ /* TEXT is always null terminated (terminator not included in len); but this
+ GTY markup arranges that PCH streaming works properly even if there is a
+ null byte in the middle of the string. */
+ const unsigned char * GTY((string_length ("1 + %h.len"))) text;
};
/* Flags for the cpp_token structure. */
typedef struct ht_identifier ht_identifier;
typedef struct ht_identifier *ht_identifier_ptr;
struct GTY(()) ht_identifier {
- const unsigned char *str;
+ /* This GTY markup arranges that the null-terminated identifier would still
+ stream to PCH correctly, if a null byte were to make its way into an
+ identifier somehow. */
+ const unsigned char * GTY((string_length ("1 + %h.len"))) str;
unsigned int len;
unsigned int hash_value;
};