SCC unification or prevailing-declaration replacement can redirect an
instance's origin tree to another input's tree. The tree-to-DIE lookup
then returns that input's DIE, while parameters and local variables
retain their original origins.
Save input DIE references by reader-cache index before the trees can be
replaced. Resolve each retained instance's encoded origin through these
references when registering it for late DWARF.
Write saved origins explicitly in WPA and incremental-link output,
including absent references, so later reads do not derive origins from
merged trees.
Tested on x86_64-pc-linux-gnu with a C/C++ checking build and
the LTO suites (gcc.dg/lto: 2012, g++.dg/lto: 1860 expected passes),
with no unexpected failures.
gcc/ChangeLog:
PR debug/126348
* lto-streamer.h (lto_die_ref, lto_die_ref_map, lto_origin_ref_kind,
lto_pending_origin_ref): New.
(lto_origin_ref_node_p): New function.
(data_in): Add reader-cache DIE references, pending origins and
methods to save and register them.
(stream_read_tree_ref): Adjust declaration.
* lto-streamer-in.cc (data_in::save_die_ref,
data_in::register_origin_refs): New methods.
(lto_read_tree_1): Save input DIEs and encoded origins. Read explicit
saved origins.
(lto_read_tree, lto_input_scc): Pass the reader-cache index.
(stream_read_tree_ref): Optionally return the encoded reference.
(lto_input_tree): Register saved origins after reading the input trees.
(lto_data_in_delete): Delete the temporary DIE-reference map.
* lto-streamer-out.cc (lto_write_tree_1): Stream saved origins and
distinguish absent origins from original tree references.
* tree-streamer.h (streamer_read_tree_body): Adjust declaration.
* tree-streamer-in.cc (lto_input_ts_decl_common_tree_pointers,
lto_input_ts_block_tree_pointers, streamer_read_tree_body): Capture
encoded abstract-origin references.
gcc/lto/ChangeLog:
PR debug/126348
* lto-common.cc (unify_scc): Discard pending origins for merged trees.
(lto_read_decls): Register origins for retained trees at the end of
each iteration.
gcc/testsuite/ChangeLog:
PR debug/126348
* g++.dg/lto/pr126348.h: New test header.
* g++.dg/lto/pr126348_0.C: New test.
* g++.dg/lto/pr126348_1.C: Likewise.
* g++.dg/lto/pr126348_2.C: Likewise.
* g++.dg/lto/pr126348-3.h: New test header.
* g++.dg/lto/pr126348-3_0.C: New test.
* g++.dg/lto/pr126348-3_1.C: Likewise.
* g++.dg/lto/pr126348-3_2.C: Likewise.
Signed-off-by: Longjun Luo <[email protected]>
---
gcc/lto-streamer-in.cc | 73 +++++++++++++++++++++++--
gcc/lto-streamer-out.cc | 18 ++++++
gcc/lto-streamer.h | 53 +++++++++++++++++-
gcc/lto/lto-common.cc | 2 +
gcc/testsuite/g++.dg/lto/pr126348-3.h | 28 ++++++++++
gcc/testsuite/g++.dg/lto/pr126348-3_0.C | 24 ++++++++
gcc/testsuite/g++.dg/lto/pr126348-3_1.C | 27 +++++++++
gcc/testsuite/g++.dg/lto/pr126348-3_2.C | 14 +++++
gcc/testsuite/g++.dg/lto/pr126348.h | 28 ++++++++++
gcc/testsuite/g++.dg/lto/pr126348_0.C | 26 +++++++++
gcc/testsuite/g++.dg/lto/pr126348_1.C | 28 ++++++++++
gcc/testsuite/g++.dg/lto/pr126348_2.C | 14 +++++
gcc/tree-streamer-in.cc | 16 +++---
gcc/tree-streamer.h | 3 +-
14 files changed, 339 insertions(+), 15 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/lto/pr126348-3.h
create mode 100644 gcc/testsuite/g++.dg/lto/pr126348-3_0.C
create mode 100644 gcc/testsuite/g++.dg/lto/pr126348-3_1.C
create mode 100644 gcc/testsuite/g++.dg/lto/pr126348-3_2.C
create mode 100644 gcc/testsuite/g++.dg/lto/pr126348.h
create mode 100644 gcc/testsuite/g++.dg/lto/pr126348_0.C
create mode 100644 gcc/testsuite/g++.dg/lto/pr126348_1.C
create mode 100644 gcc/testsuite/g++.dg/lto/pr126348_2.C
diff --git a/gcc/lto-streamer-in.cc b/gcc/lto-streamer-in.cc
index e0367dd7b8b..50c1e1f84ae 100644
--- a/gcc/lto-streamer-in.cc
+++ b/gcc/lto-streamer-in.cc
@@ -1767,11 +1767,44 @@ lto_input_variable_constructor (struct
lto_file_decl_data *file_data,
are only applied to prevailing tree nodes during tree merging. */
vec<dref_entry> dref_queue;
+/* Save REF for reader-cache slot INDEX before its tree can be replaced. */
+
+void
+data_in::save_die_ref (unsigned index, lto_die_ref ref)
+{
+ if (!die_refs)
+ die_refs = new lto_die_ref_map;
+ ref.sym = IDENTIFIER_POINTER (get_identifier (ref.sym));
+ die_refs->put (index, ref);
+}
+
+/* Resolve and register origins for retained trees. SCC unification does
+ not change the saved slot-to-DIE mappings. */
+
+void
+data_in::register_origin_refs ()
+{
+ for (const auto &entry : pending_origin_refs)
+ {
+ const lto_die_ref *ref = &entry.ref;
+ if (entry.origin > 0 && die_refs)
+ ref = die_refs->get (entry.origin - 1);
+ if (ref && ref->sym)
+ {
+ tree owner = streamer_tree_cache_get_tree (reader_cache, entry.index);
+ debug_hooks->register_external_die
+ (owner, DEBUG_ABSTRACT_ORIGIN_REF, ref->sym, ref->off);
+ }
+ }
+ pending_origin_refs.truncate (0);
+}
+
/* Read the physical representation of a tree node EXPR from
input block IB using the per-file context in DATA_IN. */
static void
-lto_read_tree_1 (class lto_input_block *ib, class data_in *data_in, tree expr)
+lto_read_tree_1 (class lto_input_block *ib, class data_in *data_in, tree expr,
+ unsigned index)
{
/* Read all the bitfield values in EXPR. Note that for LTO, we
only write language-independent bitfields, so no more unpacking is
@@ -1779,7 +1812,8 @@ lto_read_tree_1 (class lto_input_block *ib, class data_in
*data_in, tree expr)
streamer_read_tree_bitfields (ib, data_in, expr);
/* Read all the pointer fields in EXPR. */
- streamer_read_tree_body (ib, data_in, expr);
+ int origin = 0;
+ streamer_read_tree_body (ib, data_in, expr, &origin);
/* Read any LTO-specific data not read by the tree streamer. Do not use
stream_read_tree here since that flushes the dref_queue in mids of
@@ -1804,6 +1838,9 @@ lto_read_tree_1 (class lto_input_block *ib, class data_in
*data_in, tree expr)
unsigned HOST_WIDE_INT off = streamer_read_uhwi (ib);
dref_entry e = { expr, str, off };
dref_queue.safe_push (e);
+ if (debug_info_level > DINFO_LEVEL_NONE
+ && lto_origin_ref_node_p (expr))
+ data_in->save_die_ref (index, { str, off });
}
/* When there's no early DIE to refer to but dwarf2out set up
things in a way to expect that fixup. This tends to happen
@@ -1812,6 +1849,24 @@ lto_read_tree_1 (class lto_input_block *ib, class
data_in *data_in, tree expr)
DECL_ABSTRACT_ORIGIN (expr) = NULL_TREE;
}
+ if (lto_origin_ref_node_p (expr))
+ {
+ lto_die_ref ref = {};
+
+ unsigned kind = streamer_read_uhwi (ib);
+ if (kind != LTO_ORIGIN_REF_TREE)
+ origin = 0;
+ if (kind == LTO_ORIGIN_REF_DIE)
+ {
+ const char *sym = streamer_read_string (data_in, ib);
+ ref = { IDENTIFIER_POINTER (get_identifier (sym)),
+ streamer_read_uhwi (ib) };
+ }
+ if (debug_info_level > DINFO_LEVEL_NONE
+ && (ref.sym || (origin && origin != (int) index + 1)))
+ data_in->pending_origin_refs.safe_push ({ index, origin, ref });
+ }
+
#ifdef ACCEL_COMPILER
if ((VAR_P (expr)
|| TREE_CODE (expr) == PARM_DECL
@@ -1851,7 +1906,8 @@ lto_read_tree (class lto_input_block *ib, class data_in
*data_in,
structure can be resolved in subsequent calls to stream_read_tree. */
streamer_tree_cache_append (data_in->reader_cache, result, hash);
- lto_read_tree_1 (ib, data_in, result);
+ lto_read_tree_1 (ib, data_in, result,
+ data_in->reader_cache->nodes.length () - 1);
return result;
}
@@ -1908,7 +1964,7 @@ lto_input_scc (class lto_input_block *ib, class data_in
*data_in,
{
result = streamer_tree_cache_get_tree (data_in->reader_cache,
first + i);
- lto_read_tree_1 (ib, data_in, result);
+ lto_read_tree_1 (ib, data_in, result, first + i);
}
}
@@ -1920,12 +1976,15 @@ lto_input_scc (class lto_input_block *ib, class data_in
*data_in,
/* Read reference to tree from IB and DATA_IN.
This is used for streaming tree bodies where we know that
the tree is already in cache or is indexable and
- must be matched with stream_write_tree_ref. */
+ must be matched with stream_write_tree_ref. If REF is nonnull,
+ also return the encoded reference before resolving it to a tree. */
tree
-stream_read_tree_ref (lto_input_block *ib, data_in *data_in)
+stream_read_tree_ref (lto_input_block *ib, data_in *data_in, int *ref)
{
int ix = streamer_read_hwi (ib);
+ if (ref)
+ *ref = ix;
if (!ix)
return NULL_TREE;
if (ix > 0)
@@ -2030,6 +2089,7 @@ lto_input_tree (class lto_input_block *ib, class data_in
*data_in)
e.sym, e.off);
gcc_checking_assert (dref_queue.is_empty ());
}
+ data_in->register_origin_refs ();
return t;
}
@@ -2291,5 +2351,6 @@ lto_data_in_delete (class data_in *data_in)
{
data_in->globals_resolution.release ();
streamer_tree_cache_delete (data_in->reader_cache);
+ delete data_in->die_refs;
delete data_in;
}
diff --git a/gcc/lto-streamer-out.cc b/gcc/lto-streamer-out.cc
index aa1d75fa7d0..dd4d8666f82 100644
--- a/gcc/lto-streamer-out.cc
+++ b/gcc/lto-streamer-out.cc
@@ -735,6 +735,24 @@ lto_write_tree_1 (struct output_block *ob, tree expr, bool
ref_p)
else
streamer_write_string (ob, ob->main_stream, NULL, true);
}
+
+ if (lto_origin_ref_node_p (expr))
+ {
+ const char *sym;
+ unsigned HOST_WIDE_INT off;
+ if (debug_info_level > DINFO_LEVEL_NONE
+ && debug_hooks->die_ref_for_decl (expr, DEBUG_ABSTRACT_ORIGIN_REF,
+ &sym, &off))
+ {
+ streamer_write_uhwi (ob, LTO_ORIGIN_REF_DIE);
+ streamer_write_string (ob, ob->main_stream, sym, true);
+ streamer_write_uhwi (ob, off);
+ }
+ else if (flag_wpa || flag_incremental_link == INCREMENTAL_LINK_LTO)
+ streamer_write_uhwi (ob, LTO_ORIGIN_REF_NONE);
+ else
+ streamer_write_uhwi (ob, LTO_ORIGIN_REF_TREE);
+ }
}
/* Write a physical representation of tree node EXPR to output block
diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h
index d1285b87bc5..d5ba6edf89a 100644
--- a/gcc/lto-streamer.h
+++ b/gcc/lto-streamer.h
@@ -505,6 +505,38 @@ struct lto_tree_ref_encoder
};
+/* An early DIE reference independent of its tree. */
+struct GTY (()) lto_die_ref
+{
+ const char *sym;
+ unsigned HOST_WIDE_INT off;
+};
+
+/* Origin encoding appended to FUNCTION_DECL and BLOCK records after their
+ ordinary DIE reference. LGEN permits TREE. WPA and incremental LTO
+ write DIE or NONE for newly streamed trees; copied bodies retain their
+ input encoding. */
+enum lto_origin_ref_kind
+{
+ /* Use the original tree reference. No additional fields. */
+ LTO_ORIGIN_REF_TREE,
+ /* No saved origin; do not derive one from the tree.
+ No additional fields. */
+ LTO_ORIGIN_REF_NONE,
+ /* Followed by a symbol string reference and an unsigned DIE offset. */
+ LTO_ORIGIN_REF_DIE
+};
+
+/* Return true if T's LTO record includes an origin reference encoding. */
+inline bool
+lto_origin_ref_node_p (const_tree t)
+{
+ return TREE_CODE (t) == FUNCTION_DECL || TREE_CODE (t) == BLOCK;
+}
+
+typedef hash_map<int_hash<unsigned, UINT_MAX>, lto_die_ref>
+ lto_die_ref_map;
+
/* Structure to hold states of input scope. */
struct GTY((for_user)) lto_in_decl_state
{
@@ -783,6 +815,14 @@ struct output_block
};
+struct lto_pending_origin_ref
+{
+ unsigned index;
+ /* Encoded abstract-origin reference. */
+ int origin;
+ lto_die_ref ref;
+};
+
/* Data and descriptors used when reading from an LTO file. */
class data_in
{
@@ -802,12 +842,22 @@ public:
/* Cache of pickled nodes. */
struct streamer_tree_cache_d *reader_cache;
+ /* Cache slots keep their input identity when SCC unification replaces
+ their trees. Values contain no references to the discarded trees. */
+ lto_die_ref_map *die_refs = nullptr;
+
+ /* Input references awaiting registration for the current batch of trees. */
+ auto_vec<lto_pending_origin_ref> pending_origin_refs;
+
/* Cache of source code location. */
lto_location_cache location_cache;
explicit data_in (lto_file_decl_data *data_for_loc)
: location_cache{data_for_loc}
{}
+
+ void save_die_ref (unsigned index, lto_die_ref ref);
+ void register_origin_refs ();
};
@@ -919,7 +969,8 @@ hashval_t lto_input_scc (class lto_input_block *, class
data_in *,
tree lto_input_tree_1 (class lto_input_block *, class data_in *,
enum LTO_tags, hashval_t hash);
tree lto_input_tree (class lto_input_block *, class data_in *);
-tree stream_read_tree_ref (class lto_input_block *, class data_in *);
+tree stream_read_tree_ref (class lto_input_block *, class data_in *,
+ int * = nullptr);
/* In lto-streamer-out.cc */
diff --git a/gcc/lto/lto-common.cc b/gcc/lto/lto-common.cc
index 440c8ee3885..e343f775655 100644
--- a/gcc/lto/lto-common.cc
+++ b/gcc/lto/lto-common.cc
@@ -1796,6 +1796,7 @@ unify_scc (class data_in *data_in, unsigned from,
??? Do as in the size-one SCC case which involves sorting
the queue. */
dref_queue.truncate (0);
+ data_in->pending_origin_refs.truncate (0);
break;
}
@@ -1996,6 +1997,7 @@ lto_read_decls (struct lto_file_decl_data *decl_data,
const void *data,
process_new_tree (t, &hm, from, &total, data_in);
}
}
+ data_in->register_origin_refs ();
}
/* Dump type statistics. */
diff --git a/gcc/testsuite/g++.dg/lto/pr126348-3.h
b/gcc/testsuite/g++.dg/lto/pr126348-3.h
new file mode 100644
index 00000000000..31d93402cb1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/pr126348-3.h
@@ -0,0 +1,28 @@
+struct Location
+{
+ const char *file;
+ const char *function;
+ int line;
+};
+
+extern void fail (int, const char *, const Location &)
+ __attribute__ ((noreturn, cold, noipa));
+extern void note (const char *, int) __attribute__ ((cold, noipa));
+
+static const char source_file[] = __BASE_FILE__;
+
+struct Buffer
+{
+ int length;
+
+ __attribute__ ((used)) int printable_length () const
+ {
+ if (__builtin_expect (length < 1024, 1))
+ return length;
+ const Location location = { source_file, __func__, __LINE__ };
+ note (location.file, location.line);
+ note (location.function, length);
+ note (location.file, length + 1);
+ fail (3, "length < 1024", location);
+ }
+};
diff --git a/gcc/testsuite/g++.dg/lto/pr126348-3_0.C
b/gcc/testsuite/g++.dg/lto/pr126348-3_0.C
new file mode 100644
index 00000000000..e8256aa0689
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/pr126348-3_0.C
@@ -0,0 +1,24 @@
+/* PR debug/126348 */
+/* Different options keep the COMDAT declarations distinct until prevailing
+ decl replacement. That replacement must not invalidate the split
+ function's origin from pr126348-3_1.C. */
+/* { dg-lto-do link } */
+/* { dg-skip-if "No DWARF debug support" { hppa*-*-hpux* } } */
+/* { dg-skip-if "AIX DWARF5" { powerpc-ibm-aix* } } */
+/* { dg-lto-options { { -O2 -g -gdwarf-5 -dA -save-temps -flto
-flto-partition=one -fno-ipa-icf --param=max-inline-insns-auto=100 } } } */
+/* { dg-extra-ld-options "-r -nostdlib -flinker-output=nolto-rel" } */
+/* { dg-final { scan-lto-assembler
"DW_TAG_subprogram\\)(?:\[^\n\]*\n){1,6}\[^\n\]*pr126348_3_1\[^\n\]*DW_AT_abstract_origin(?:\[^\n\]*\n){1,4}\[^\n\]*DW_AT_(?:low_pc|ranges)(?:\[^\n\]*\n){1,8}\[^\n\]*DW_TAG_formal_parameter\\)(?:\[^\n\]*\n){1,6}\[^\n\]*pr126348_3_1\[^\n\]*DW_AT_abstract_origin(?:\[^\n\]*\n){1,4}\[^\n\]*DW_TAG_variable\\)(?:\[^\n\]*\n){1,6}\[^\n\]*pr126348_3_1\[^\n\]*DW_AT_abstract_origin"
} } */
+
+#include "pr126348-3.h"
+
+__attribute__ ((noinline)) int
+one (const Buffer &buffer)
+{
+ return buffer.printable_length ();
+}
+
+__attribute__ ((noinline)) int
+one_extra (const Buffer &buffer)
+{
+ return buffer.printable_length ();
+}
diff --git a/gcc/testsuite/g++.dg/lto/pr126348-3_1.C
b/gcc/testsuite/g++.dg/lto/pr126348-3_1.C
new file mode 100644
index 00000000000..da36e18e2f9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/pr126348-3_1.C
@@ -0,0 +1,27 @@
+/* { dg-options "-fno-strict-aliasing" } */
+
+#include "pr126348-3.h"
+
+void
+fail (int, const char *, const Location &)
+{
+ __builtin_trap ();
+}
+
+void
+note (const char *, int)
+{
+ asm volatile ("" ::: "memory");
+}
+
+__attribute__ ((noinline)) int
+two (const Buffer &buffer)
+{
+ return buffer.printable_length ();
+}
+
+__attribute__ ((noinline)) int
+two_extra (const Buffer &buffer)
+{
+ return buffer.printable_length ();
+}
diff --git a/gcc/testsuite/g++.dg/lto/pr126348-3_2.C
b/gcc/testsuite/g++.dg/lto/pr126348-3_2.C
new file mode 100644
index 00000000000..f13c6ea4455
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/pr126348-3_2.C
@@ -0,0 +1,14 @@
+#include "pr126348-3.h"
+
+__attribute__ ((noinline)) int one (const Buffer &);
+__attribute__ ((noinline)) int one_extra (const Buffer &);
+__attribute__ ((noinline)) int two (const Buffer &);
+__attribute__ ((noinline)) int two_extra (const Buffer &);
+
+int
+main (int argc, char **)
+{
+ Buffer buffer = { argc };
+ return one (buffer) + one_extra (buffer)
+ + two (buffer) + two_extra (buffer);
+}
diff --git a/gcc/testsuite/g++.dg/lto/pr126348.h
b/gcc/testsuite/g++.dg/lto/pr126348.h
new file mode 100644
index 00000000000..eac6698064a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/pr126348.h
@@ -0,0 +1,28 @@
+struct Location
+{
+ const char *file;
+ const char *function;
+ int line;
+};
+
+extern void fail (int, const char *, const Location &)
+ __attribute__ ((noreturn, cold, noipa));
+extern void note (const char *, int) __attribute__ ((cold, noipa));
+
+static const char source_file[] = __BASE_FILE__;
+
+struct Buffer
+{
+ int length;
+
+ int printable_length () const
+ {
+ if (__builtin_expect (length < 1024, 1))
+ return length;
+ const Location location = { source_file, __func__, __LINE__ };
+ note (location.file, location.line);
+ note (location.function, length);
+ note (location.file, length + 1);
+ fail (3, "length < 1024", location);
+ }
+};
diff --git a/gcc/testsuite/g++.dg/lto/pr126348_0.C
b/gcc/testsuite/g++.dg/lto/pr126348_0.C
new file mode 100644
index 00000000000..ffe3f4486c5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/pr126348_0.C
@@ -0,0 +1,26 @@
+/* PR debug/126348 */
+/* Verify that an out-of-line split function and its direct children retain
+ the same input TU provenance, and that the function has an address-bearing
+ late DIE. */
+/* { dg-lto-do link } */
+/* { dg-skip-if "No DWARF debug support" { hppa*-*-hpux* } } */
+/* { dg-skip-if "AIX DWARF5" { powerpc-ibm-aix* } } */
+/* { dg-lto-options { { -O2 -g -gdwarf-5 -dA -save-temps -flto
-flto-partition=one -fno-ipa-icf --param=max-inline-insns-auto=100 } } } */
+/* { dg-extra-ld-options "-r -nostdlib -flinker-output=nolto-rel" } */
+/* { dg-final { scan-lto-assembler
"DW_TAG_subprogram\\)(?:\[^\n\]*\n){1,6}\[^\n\]*pr126348_0\[^\n\]*DW_AT_abstract_origin(?:\[^\n\]*\n){1,4}\[^\n\]*DW_AT_(?:low_pc|ranges)(?:\[^\n\]*\n){1,8}\[^\n\]*DW_TAG_formal_parameter\\)(?:\[^\n\]*\n){1,6}\[^\n\]*pr126348_0\[^\n\]*DW_AT_abstract_origin(?:\[^\n\]*\n){1,4}\[^\n\]*DW_TAG_variable\\)(?:\[^\n\]*\n){1,6}\[^\n\]*pr126348_0\[^\n\]*DW_AT_abstract_origin"
} } */
+/* { dg-final { scan-lto-assembler
"DW_TAG_subprogram\\)(?:\[^\n\]*\n){1,6}\[^\n\]*pr126348_1\[^\n\]*DW_AT_abstract_origin(?:\[^\n\]*\n){1,4}\[^\n\]*DW_AT_(?:low_pc|ranges)(?:\[^\n\]*\n){1,8}\[^\n\]*DW_TAG_formal_parameter\\)(?:\[^\n\]*\n){1,6}\[^\n\]*pr126348_1\[^\n\]*DW_AT_abstract_origin(?:\[^\n\]*\n){1,4}\[^\n\]*DW_TAG_variable\\)(?:\[^\n\]*\n){1,6}\[^\n\]*pr126348_1\[^\n\]*DW_AT_abstract_origin"
} } */
+
+
+#include "pr126348.h"
+
+__attribute__ ((noinline)) int
+one (const Buffer &buffer)
+{
+ return buffer.printable_length ();
+}
+
+__attribute__ ((noinline)) int
+one_extra (const Buffer &buffer)
+{
+ return buffer.printable_length ();
+}
diff --git a/gcc/testsuite/g++.dg/lto/pr126348_1.C
b/gcc/testsuite/g++.dg/lto/pr126348_1.C
new file mode 100644
index 00000000000..bad1a25aa63
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/pr126348_1.C
@@ -0,0 +1,28 @@
+#include "pr126348.h"
+
+__attribute__ ((noinline)) int one (const Buffer &);
+__attribute__ ((noinline)) int one_extra (const Buffer &);
+
+void
+fail (int, const char *, const Location &)
+{
+ __builtin_trap ();
+}
+
+void
+note (const char *, int)
+{
+ asm volatile ("" ::: "memory");
+}
+
+__attribute__ ((noinline)) int
+two (const Buffer &buffer)
+{
+ return buffer.printable_length ();
+}
+
+__attribute__ ((noinline)) int
+two_extra (const Buffer &buffer)
+{
+ return buffer.printable_length ();
+}
diff --git a/gcc/testsuite/g++.dg/lto/pr126348_2.C
b/gcc/testsuite/g++.dg/lto/pr126348_2.C
new file mode 100644
index 00000000000..7a4015f3b49
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/pr126348_2.C
@@ -0,0 +1,14 @@
+#include "pr126348.h"
+
+__attribute__ ((noinline)) int one (const Buffer &);
+__attribute__ ((noinline)) int one_extra (const Buffer &);
+__attribute__ ((noinline)) int two (const Buffer &);
+__attribute__ ((noinline)) int two_extra (const Buffer &);
+
+int
+main (int argc, char **)
+{
+ Buffer buffer = { argc };
+ return one (buffer) + one_extra (buffer)
+ + two (buffer) + two_extra (buffer);
+}
diff --git a/gcc/tree-streamer-in.cc b/gcc/tree-streamer-in.cc
index 45ba2732d3a..b1d8847a20a 100644
--- a/gcc/tree-streamer-in.cc
+++ b/gcc/tree-streamer-in.cc
@@ -771,12 +771,13 @@ lto_input_ts_decl_minimal_tree_pointers (class
lto_input_block *ib,
static void
lto_input_ts_decl_common_tree_pointers (class lto_input_block *ib,
- class data_in *data_in, tree expr)
+ class data_in *data_in, tree expr,
+ int *origin_ref)
{
DECL_SIZE (expr) = stream_read_tree_ref (ib, data_in);
DECL_SIZE_UNIT (expr) = stream_read_tree_ref (ib, data_in);
DECL_ATTRIBUTES (expr) = stream_read_tree_ref (ib, data_in);
- DECL_ABSTRACT_ORIGIN (expr) = stream_read_tree_ref (ib, data_in);
+ DECL_ABSTRACT_ORIGIN (expr) = stream_read_tree_ref (ib, data_in, origin_ref);
if ((VAR_P (expr) || TREE_CODE (expr) == PARM_DECL)
&& DECL_HAS_VALUE_EXPR_P (expr))
@@ -978,12 +979,13 @@ lto_input_ts_exp_tree_pointers (class lto_input_block *ib,
static void
lto_input_ts_block_tree_pointers (class lto_input_block *ib,
- class data_in *data_in, tree expr)
+ class data_in *data_in, tree expr,
+ int *origin_ref)
{
BLOCK_VARS (expr) = streamer_read_chain (ib, data_in);
BLOCK_SUPERCONTEXT (expr) = stream_read_tree_ref (ib, data_in);
- BLOCK_ABSTRACT_ORIGIN (expr) = stream_read_tree_ref (ib, data_in);
+ BLOCK_ABSTRACT_ORIGIN (expr) = stream_read_tree_ref (ib, data_in,
origin_ref);
/* We may end up prevailing a decl with DECL_ORIGIN (t) != t here
which breaks the invariant that BLOCK_ABSTRACT_ORIGIN is the
ultimate origin. Fixup here.
@@ -1107,7 +1109,7 @@ lto_input_ts_omp_clause_tree_pointers (class
lto_input_block *ib,
void
streamer_read_tree_body (class lto_input_block *ib, class data_in *data_in,
- tree expr)
+ tree expr, int *origin_ref)
{
enum tree_code code;
@@ -1129,7 +1131,7 @@ streamer_read_tree_body (class lto_input_block *ib, class
data_in *data_in,
lto_input_ts_decl_minimal_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
- lto_input_ts_decl_common_tree_pointers (ib, data_in, expr);
+ lto_input_ts_decl_common_tree_pointers (ib, data_in, expr, origin_ref);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON))
lto_input_ts_decl_non_common_tree_pointers (ib, data_in, expr);
@@ -1159,7 +1161,7 @@ streamer_read_tree_body (class lto_input_block *ib, class
data_in *data_in,
lto_input_ts_exp_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
- lto_input_ts_block_tree_pointers (ib, data_in, expr);
+ lto_input_ts_block_tree_pointers (ib, data_in, expr, origin_ref);
if (CODE_CONTAINS_STRUCT (code, TS_BINFO))
lto_input_ts_binfo_tree_pointers (ib, data_in, expr);
diff --git a/gcc/tree-streamer.h b/gcc/tree-streamer.h
index 942548ec3cd..5e3c60389c9 100644
--- a/gcc/tree-streamer.h
+++ b/gcc/tree-streamer.h
@@ -61,7 +61,8 @@ struct streamer_tree_cache_d
tree streamer_read_string_cst (class data_in *, class lto_input_block *);
tree streamer_alloc_tree (class lto_input_block *, class data_in *,
enum LTO_tags);
-void streamer_read_tree_body (class lto_input_block *, class data_in *, tree);
+void streamer_read_tree_body (class lto_input_block *, class data_in *, tree,
+ int *);
tree streamer_get_pickled_tree (class lto_input_block *, class data_in *);
void streamer_read_tree_bitfields (class lto_input_block *,
class data_in *, tree);
--
2.53.0