aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/doc/gty.texi21
-rw-r--r--gcc/gengtype.cc25
-rw-r--r--gcc/ggc-common.cc7
-rw-r--r--gcc/ggc.h4
-rw-r--r--gcc/stringpool.cc7
-rw-r--r--gcc/testsuite/g++.dg/pch/pch-string-nulls.C3
-rw-r--r--gcc/testsuite/g++.dg/pch/pch-string-nulls.Hsbin0 -> 78 bytes
-rw-r--r--libcpp/include/cpplib.h6
-rw-r--r--libcpp/include/symtab.h5
9 files changed, 68 insertions, 10 deletions
diff --git a/gcc/doc/gty.texi b/gcc/doc/gty.texi
index 81aafd1..4f791b3 100644
--- a/gcc/doc/gty.texi
+++ b/gcc/doc/gty.texi
@@ -196,7 +196,26 @@ static GTY((length("reg_known_value_size"))) rtx *reg_known_value;
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
diff --git a/gcc/gengtype.cc b/gcc/gengtype.cc
index 4236343..28bf05e 100644
--- a/gcc/gengtype.cc
+++ b/gcc/gengtype.cc
@@ -2403,7 +2403,7 @@ struct write_types_data
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);
@@ -2537,7 +2537,7 @@ output_mangled_typename (outf_p of, const_type_p t)
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;
@@ -2576,7 +2576,7 @@ const char *
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;
}
@@ -2700,6 +2700,8 @@ walk_type (type_p t, struct walk_type_data *d)
;
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);
@@ -3251,7 +3253,22 @@ write_types_process_field (type_p f, const struct walk_type_data *d)
{
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,
diff --git a/gcc/ggc-common.cc b/gcc/ggc-common.cc
index 8b3389e..62da09d 100644
--- a/gcc/ggc-common.cc
+++ b/gcc/ggc-common.cc
@@ -253,7 +253,8 @@ static vec<void *> reloc_addrs_vec;
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;
@@ -273,7 +274,9 @@ gt_pch_note_object (void *obj, void *note_ptr_cookie,
(*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);
diff --git a/gcc/ggc.h b/gcc/ggc.h
index aeec1ba..7bc74ec 100644
--- a/gcc/ggc.h
+++ b/gcc/ggc.h
@@ -44,7 +44,8 @@ typedef void (*gt_handle_reorder) (void *, void *, gt_pointer_operator,
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. */
@@ -101,6 +102,7 @@ extern int ggc_marked_p (const void *);
/* 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. */
diff --git a/gcc/stringpool.cc b/gcc/stringpool.cc
index 57509d5..20dbef5 100644
--- a/gcc/stringpool.cc
+++ b/gcc/stringpool.cc
@@ -196,6 +196,13 @@ gt_pch_n_S (const void *x)
&gt_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),
+ &gt_pch_p_S, string_len);
+}
+
/* User-callable entry point for marking string X. */
diff --git a/gcc/testsuite/g++.dg/pch/pch-string-nulls.C b/gcc/testsuite/g++.dg/pch/pch-string-nulls.C
new file mode 100644
index 0000000..dfeb21a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pch/pch-string-nulls.C
@@ -0,0 +1,3 @@
+// { dg-do compile { target c++11 } }
+#include "pch-string-nulls.H"
+static_assert (X[4] == '[' && X[5] == '!' && X[6] == ']', "error");
diff --git a/gcc/testsuite/g++.dg/pch/pch-string-nulls.Hs b/gcc/testsuite/g++.dg/pch/pch-string-nulls.Hs
new file mode 100644
index 0000000..02f4317
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pch/pch-string-nulls.Hs
Binary files differ
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index d5ef12a..1d34c00 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -179,7 +179,11 @@ enum c_lang {CLK_GNUC89 = 0, CLK_GNUC99, CLK_GNUC11, CLK_GNUC17, CLK_GNUC2X,
/* 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. */
diff --git a/libcpp/include/symtab.h b/libcpp/include/symtab.h
index 53efe6c..8b45fd5 100644
--- a/libcpp/include/symtab.h
+++ b/libcpp/include/symtab.h
@@ -29,7 +29,10 @@ along with this program; see the file COPYING3. If not see
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;
};