This patch adds minimal type merging. It unifies the existence of types for a struct decl. The method is to emit a merge key for the type when we emit a merge key for the struct decl.
Test x4structover1.cc is now passing. The next step is to merge struct definitions. For that we have test cases x*incomplete*, which progressively add more information to the classes in different configurations of pph files. Tested on x64. Index: gcc/testsuite/ChangeLog.pph 2012-02-01 Lawrence Crowl <cr...@google.com> * g++.dg/pph/x4structover1.cc: Mark fixed. * g++.dg/pph/a0incomplete2.hi: New. * g++.dg/pph/a0incomplete3.hi: New. * g++.dg/pph/a0incomplete4.cci: New. * g++.dg/pph/x0incomplete1.h: New. * g++.dg/pph/x0incomplete2.h: New. * g++.dg/pph/x0incomplete3.h: New. * g++.dg/pph/x1incomplete3.h: New. * g++.dg/pph/x1incomplete4.cc: New. * g++.dg/pph/x2incomplete4.cc: New. * g++.dg/pph/x3incomplete412.cc: New. * g++.dg/pph/x3incomplete413.cc: New. * g++.dg/pph/x4incomplete4123.cc: New. * g++.dg/pph/x4incomplete4321.cc: New. Index: gcc/cp/ChangeLog.pph 2012-02-01 Lawrence Crowl <cr...@google.com> * error.c (dump_function_decl): Add protection against NULL. * pph-out.c (pph_out_merge_key_tree): Write merge keys for struct types, as opposed to decls. * pph-in.c (pph_in_merge_tree_body): Save chains in decls only. (pph_in_merge_key_tree): Read merge keys for struct types. Split handling into two phases, cache insertion (which is before the trace front) and sub-tree reading. Index: gcc/testsuite/g++.dg/pph/x1incomplete3.h =================================================================== --- gcc/testsuite/g++.dg/pph/x1incomplete3.h (revision 0) +++ gcc/testsuite/g++.dg/pph/x1incomplete3.h (revision 0) @@ -0,0 +1,7 @@ +#ifndef X0INCOMPLETE3_H +#define X0INCOMPLETE3_H + +#include "x0incomplete2.h" +#include "a0incomplete3.hi" + +#endif Index: gcc/testsuite/g++.dg/pph/x0incomplete2.h =================================================================== --- gcc/testsuite/g++.dg/pph/x0incomplete2.h (revision 0) +++ gcc/testsuite/g++.dg/pph/x0incomplete2.h (revision 0) @@ -0,0 +1,6 @@ +#ifndef X0INCOMPLETE2_H +#define X0INCOMPLETE2_H + +#include "a0incomplete2.hi" + +#endif Index: gcc/testsuite/g++.dg/pph/x2incomplete4.cc =================================================================== --- gcc/testsuite/g++.dg/pph/x2incomplete4.cc (revision 0) +++ gcc/testsuite/g++.dg/pph/x2incomplete4.cc (revision 0) @@ -0,0 +1,5 @@ +// { dg-xfail-if "ICE" { "*-*-*" } { "-fpph-map=pph.map" } } +// { dg-bogus "internal compiler error: in import_export_decl, at cp/decl2.c" "" { xfail *-*-* } 0 } + +#include "x1incomplete3.h" +#include "a0incomplete4.cci" Index: gcc/testsuite/g++.dg/pph/x0incomplete3.h =================================================================== --- gcc/testsuite/g++.dg/pph/x0incomplete3.h (revision 0) +++ gcc/testsuite/g++.dg/pph/x0incomplete3.h (revision 0) @@ -0,0 +1,7 @@ +#ifndef X0INCOMPLETE3_H +#define X0INCOMPLETE3_H + +#include "a0incomplete2.hi" +#include "a0incomplete3.hi" + +#endif Index: gcc/testsuite/g++.dg/pph/x1incomplete4.cc =================================================================== --- gcc/testsuite/g++.dg/pph/x1incomplete4.cc (revision 0) +++ gcc/testsuite/g++.dg/pph/x1incomplete4.cc (revision 0) @@ -0,0 +1,2 @@ +#include "x0incomplete3.h" +#include "a0incomplete4.cci" Index: gcc/testsuite/g++.dg/pph/a0incomplete4.cci =================================================================== --- gcc/testsuite/g++.dg/pph/a0incomplete4.cci (revision 0) +++ gcc/testsuite/g++.dg/pph/a0incomplete4.cci (revision 0) @@ -0,0 +1,5 @@ +int query( copies arg ) +{ + copies var( arg ); + return var.value(); +} Index: gcc/testsuite/g++.dg/pph/x4incomplete4123.cc =================================================================== --- gcc/testsuite/g++.dg/pph/x4incomplete4123.cc (revision 0) +++ gcc/testsuite/g++.dg/pph/x4incomplete4123.cc (revision 0) @@ -0,0 +1,4 @@ +#include "x0incomplete1.h" +#include "x0incomplete2.h" +#include "x0incomplete3.h" +#include "a0incomplete4.cci" Index: gcc/testsuite/g++.dg/pph/x3incomplete412.cc =================================================================== --- gcc/testsuite/g++.dg/pph/x3incomplete412.cc (revision 0) +++ gcc/testsuite/g++.dg/pph/x3incomplete412.cc (revision 0) @@ -0,0 +1,4 @@ +#include "x0incomplete1.h" +#include "x0incomplete2.h" +#include "a0incomplete3.hi" +#include "a0incomplete4.cci" Index: gcc/testsuite/g++.dg/pph/a0incomplete2.hi =================================================================== --- gcc/testsuite/g++.dg/pph/a0incomplete2.hi (revision 0) +++ gcc/testsuite/g++.dg/pph/a0incomplete2.hi (revision 0) @@ -0,0 +1,12 @@ +#ifndef A0INCOMPLETE2_HI +#define A0INCOMPLETE2_HI + +struct copies +{ + copies(); + copies( const copies &arg ); + int value(); + int field; +}; + +#endif Index: gcc/testsuite/g++.dg/pph/x4structover1.cc =================================================================== --- gcc/testsuite/g++.dg/pph/x4structover1.cc (revision 183821) +++ gcc/testsuite/g++.dg/pph/x4structover1.cc (working copy) @@ -1,7 +1,3 @@ -// { dg-xfail-if "BOGUS TYPE MERGE" { "*-*-*" } { "-fpph-map=pph.map" } } -// This test fails because even if we merge type decls, -// we are not merging the corresponding types. - #include "x0structover1.h" #include "x0structover2.h" Index: gcc/testsuite/g++.dg/pph/x4incomplete4321.cc =================================================================== --- gcc/testsuite/g++.dg/pph/x4incomplete4321.cc (revision 0) +++ gcc/testsuite/g++.dg/pph/x4incomplete4321.cc (revision 0) @@ -0,0 +1,7 @@ +// pph asm xdiff 64351 +// XFAIL missing constructors + +#include "x0incomplete3.h" +#include "x0incomplete2.h" +#include "x0incomplete1.h" +#include "a0incomplete4.cci" Index: gcc/testsuite/g++.dg/pph/x3incomplete413.cc =================================================================== --- gcc/testsuite/g++.dg/pph/x3incomplete413.cc (revision 0) +++ gcc/testsuite/g++.dg/pph/x3incomplete413.cc (revision 0) @@ -0,0 +1,3 @@ +#include "x0incomplete1.h" +#include "x0incomplete3.h" +#include "a0incomplete4.cci" Index: gcc/testsuite/g++.dg/pph/a0incomplete3.hi =================================================================== --- gcc/testsuite/g++.dg/pph/a0incomplete3.hi (revision 0) +++ gcc/testsuite/g++.dg/pph/a0incomplete3.hi (revision 0) @@ -0,0 +1,21 @@ +#ifndef A0INCOMPLETE3_HI +#define A0INCOMPLETE3_HI + +inline copies::copies() +: + field( 0 ) +{ +} + +inline copies::copies( const copies &arg ) +: + field( arg.field + 1 ) +{ +} + +inline int copies::value() +{ + return field; +} + +#endif Index: gcc/testsuite/g++.dg/pph/x0incomplete1.h =================================================================== --- gcc/testsuite/g++.dg/pph/x0incomplete1.h (revision 0) +++ gcc/testsuite/g++.dg/pph/x0incomplete1.h (revision 0) @@ -0,0 +1,6 @@ +#ifndef X0INCOMPLETE1_H +#define X0INCOMPLETE1_H + +struct stuff; + +#endif Index: gcc/cp/error.c =================================================================== --- gcc/cp/error.c (revision 183821) +++ gcc/cp/error.c (working copy) @@ -1351,7 +1351,7 @@ static void dump_function_decl (tree t, int flags) { tree fntype; - tree parmtypes; + tree parmtypes, argtypes; tree cname = NULL_TREE; tree template_args = NULL_TREE; tree template_parms = NULL_TREE; @@ -1393,7 +1393,12 @@ dump_function_decl (tree t, int flags) } fntype = TREE_TYPE (t); - parmtypes = FUNCTION_FIRST_USER_PARMTYPE (t); + gcc_assert (fntype) + argtypes = TYPE_ARG_TYPES (fntype); + if (argtypes) + parmtypes = skip_artificial_parms_for (t, argtypes); + else + parmtypes = NULL; if (DECL_CLASS_SCOPE_P (t)) cname = DECL_CONTEXT (t); Index: gcc/cp/pph-out.c =================================================================== --- gcc/cp/pph-out.c (revision 183821) +++ gcc/cp/pph-out.c (working copy) @@ -2353,11 +2353,19 @@ pph_out_merge_key_tree (pph_stream *stre /* Write the merge name, used to lookup EXPR in the reader's context and merge if necessary. */ pph_out_merge_name (stream, expr); + + if (TREE_CODE (expr) == TYPE_DECL) + { + bool is_implicit = DECL_IMPLICIT_TYPEDEF_P (expr); + tree type = TREE_TYPE (expr); + pph_out_bool (stream, is_implicit); + if (is_implicit) + pph_out_merge_key_tree (stream, type); + } } else { gcc_assert (TYPE_P (expr)); - gcc_assert (false); } if (flag_pph_tracer) Index: gcc/cp/pph-in.c =================================================================== --- gcc/cp/pph-in.c (revision 183821) +++ gcc/cp/pph-in.c (working copy) @@ -2116,11 +2116,6 @@ pph_in_merge_tree_body (pph_stream *stre struct lto_input_block *ib = stream->encoder.r.ib; struct data_in *data_in = stream->encoder.r.data_in; - /* If we are reading a merge body, it means that EXPR is already in - some chain. Given that EXPR may now be in a different location - in the chain, we need to make sure we do not lose it. */ - tree saved_expr_chain = TREE_CHAIN (expr); - /* Read the language-independent parts of EXPR's body. */ streamer_read_tree_body (ib, data_in, expr); @@ -2128,7 +2123,15 @@ pph_in_merge_tree_body (pph_stream *stre switch (TREE_CODE_CLASS (TREE_CODE (expr))) { case tcc_declaration: + { + /* If we are reading a merge body, it means that EXPR is already in + some chain. Given that EXPR may now be in a different location + in the chain, we need to make sure we do not lose it. + FIXME pph: We should just not save TREE_CHAIN for merge bodies. */ + tree saved_expr_chain = TREE_CHAIN (expr); pph_in_merge_tcc_declaration (stream, expr); + TREE_CHAIN (expr) = saved_expr_chain; + } break; case tcc_type: @@ -2140,10 +2143,6 @@ pph_in_merge_tree_body (pph_stream *stre pph_tree_code_text (TREE_CODE (expr))); break; } - - /* Restore TREE_CHAIN if necessary. FIXME pph, we should just not - save TREE_CHAIN for merge bodies. */ - TREE_CHAIN (expr) = saved_expr_chain; } @@ -2413,7 +2412,7 @@ pph_in_merge_key_tree (pph_stream *strea unsigned image_ix, ix; tree read_expr, expr; bool fully_read_p; - const char *name; + const char *name = "?"; marker = pph_in_start_record (stream, &image_ix, &ix, PPH_any_tree); if (marker == PPH_RECORD_END) @@ -2426,36 +2425,52 @@ pph_in_merge_key_tree (pph_stream *strea language-independent bitfields for the new tree. */ read_expr = pph_in_tree_header (stream, &fully_read_p); gcc_assert (!fully_read_p); + gcc_assert (chain); if (DECL_P (read_expr)) { - gcc_assert (chain); name = pph_in_string (stream); /* If we are merging into an existing CHAIN. Look for a match in CHAIN to READ_EXPR's header. If we found a match, EXPR will be the existing tree that matches READ_EXPR. Otherwise, EXPR is the newly allocated READ_EXPR. */ expr = pph_merge_into_chain (read_expr, name, chain); - gcc_assert (expr != NULL); - pph_cache_insert_at (&stream->cache, expr, ix, - pph_tree_code_to_tag (expr)); + } + else + { + gcc_assert (TYPE_P (read_expr)); + if (*chain) + expr = *chain; + else + expr = read_expr; + } + gcc_assert (expr != NULL); + pph_cache_insert_at (&stream->cache, expr, ix, + pph_tree_code_to_tag (expr)); - if (flag_pph_tracer) - pph_trace_tree (expr, name, pph_trace_front, - expr == read_expr ? pph_trace_unmerged_key - : pph_trace_merged_key); + if (flag_pph_tracer) + pph_trace_tree (expr, name, pph_trace_front, + expr == read_expr ? pph_trace_unmerged_key + : pph_trace_merged_key); - if (flag_pph_tracer) - pph_trace_tree (expr, name, pph_trace_back, - expr == read_expr ? pph_trace_unmerged_key - : pph_trace_merged_key); + if (DECL_P (read_expr)) + { + if (TREE_CODE (expr) == TYPE_DECL) + { + bool is_implicit = pph_in_bool (stream); + if (is_implicit) + pph_in_merge_key_tree (stream, &(TREE_TYPE (expr))); + } } else { - gcc_assert (TYPE_P (read_expr)); - gcc_assert (false); } + if (flag_pph_tracer) + pph_trace_tree (expr, name, pph_trace_back, + expr == read_expr ? pph_trace_unmerged_key + : pph_trace_merged_key); + return expr; } -- This patch is available for review at http://codereview.appspot.com/5620047