This patch writes the tree header for mutated trees. This write is necessary to get updated attribute information from the info bits. On read, these bits are then merged into the existing tree.
Test x2incomplete4.cc is now generating assembly. However, it erroneously generates an inline default constructor. This error likely occurs because pph_in_symtab actions are handled after reading each pph file, rather merged and emitted after all pph files are read. Diego will address this symtab merge. Since we are now merging types, this patch includes a fix to more aggressively trace types. In addition, there are a couple of fixes to protect against null pointers. Tested on x64. Index: gcc/testsuite/ChangeLog.pph 2012-02-23 Lawrence Crowl <cr...@google.com> * g++.dg/pph/x2incomplete4.cc: Make expected assembley diff. Index: gcc/cp/ChangeLog.pph 2012-02-23 Lawrence Crowl <cr...@google.com> * pph-core.c (pph_trace_tree): Trace trees as well as decls. * cp-tree.h (class_of_this_parm): Protect against null type. * error.c (dump_function_decl): Protect against null type. * pph-out.c (pph_out_tree): Write tree header for mutated trees. * pph-in.c (pph_merge_tree_attributes): New. (pph_in_merge_key_tree): Merge tree attributes. (pph_in_tree): Read tree header for mutated trees. Merge their attributes. Index: gcc/testsuite/g++.dg/pph/x2incomplete4.cc =================================================================== --- gcc/testsuite/g++.dg/pph/x2incomplete4.cc (revision 184521) +++ gcc/testsuite/g++.dg/pph/x2incomplete4.cc (working copy) @@ -1,5 +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 } +// pph asm xdiff 21766 +// copies::copies() is wrongly generated #include "x1incomplete3.h" #include "a0incomplete4.cci" Index: gcc/cp/pph-core.c =================================================================== --- gcc/cp/pph-core.c (revision 184521) +++ gcc/cp/pph-core.c (working copy) @@ -381,7 +381,7 @@ pph_trace_tree (tree t, const char *name enum pph_trace_end end, enum pph_trace_kind kind) { char end_char, kind_char, decl_char; - bool is_merge, is_decl; + bool is_merge, is_decl, is_type; bool emit = false; switch (kind) @@ -418,6 +418,7 @@ pph_trace_tree (tree t, const char *name end_char = end == pph_trace_front ? '{' : '}'; is_decl = DECL_P (t); + is_type = TYPE_P (t); if (is_decl) decl_char = 'D'; else if (TYPE_P (t)) @@ -425,9 +426,9 @@ pph_trace_tree (tree t, const char *name else decl_char = '.'; - if (is_merge && is_decl && flag_pph_tracer >= 2) + if (is_merge && flag_pph_tracer >= 2) emit = true; - else if ((is_merge || is_decl) && flag_pph_tracer >= 3) + else if ((is_merge || is_decl || is_type) && flag_pph_tracer >= 3) emit = true; else if (!EXPR_P (t) && flag_pph_tracer >= 4) emit = true; Index: gcc/cp/error.c =================================================================== --- gcc/cp/error.c (revision 184521) +++ gcc/cp/error.c (working copy) @@ -1446,8 +1446,13 @@ dump_function_decl (tree t, int flags) if (TREE_CODE (fntype) == METHOD_TYPE) { + tree type_this = type_of_this_parm (fntype); + tree type_class = type_this ? TREE_TYPE (type_this) : NULL; pp_base (cxx_pp)->padding = pp_before; - pp_cxx_cv_qualifier_seq (cxx_pp, class_of_this_parm (fntype)); + if (type_class) + pp_cxx_cv_qualifier_seq (cxx_pp, class_of_this_parm (fntype)); + else + pp_cxx_ws_string (cxx_pp, M_("<null>"));; } if (flags & TFF_EXCEPTION_SPECIFICATION) Index: gcc/cp/pph-out.c =================================================================== --- gcc/cp/pph-out.c (revision 184521) +++ gcc/cp/pph-out.c (working copy) @@ -2355,16 +2355,7 @@ pph_out_tree (pph_stream *stream, tree e if (marker == PPH_RECORD_START || marker == PPH_RECORD_START_MUTATED) { - /* This is the first time we see EXPR, write it out. */ - if (marker == PPH_RECORD_START) - { - /* We only need to write EXPR's header if it needs to be - re-allocated when reading. If we are writing the mutated - state of an existing tree, then we only need to write its - body. */ - pph_out_tree_header (stream, expr); - } - + pph_out_tree_header (stream, expr); pph_out_tree_body (stream, expr); } else if (marker == PPH_RECORD_START_MERGE_BODY) Index: gcc/cp/cp-tree.h =================================================================== --- gcc/cp/cp-tree.h (revision 184521) +++ gcc/cp/cp-tree.h (working copy) @@ -4836,7 +4836,8 @@ type_of_this_parm (const_tree fntype) static inline tree class_of_this_parm (const_tree fntype) { - return TREE_TYPE (type_of_this_parm (fntype)); + tree type_this = type_of_this_parm (fntype); + return type_this ? TREE_TYPE (type_this) : NULL; } /* A parameter list indicating for a function with no parameters, Index: gcc/cp/pph-in.c =================================================================== --- gcc/cp/pph-in.c (revision 184521) +++ gcc/cp/pph-in.c (working copy) @@ -2502,6 +2502,39 @@ pph_in_merge_body_namespace_decl (pph_st } +/* Merge the attributes of a READ_EXPR into an existing EXPR. */ + +static void +pph_merge_tree_attributes (tree expr, tree read_expr) +{ + enum tree_code code = TREE_CODE (read_expr); + /* Collected from print_node. */ + TREE_USED (expr) |= TREE_USED (read_expr); + TREE_NOTHROW (expr) |= TREE_NOTHROW (read_expr); + TREE_PUBLIC (expr) |= TREE_PUBLIC (read_expr); + TREE_PRIVATE (expr) |= TREE_PRIVATE (read_expr); + TREE_PROTECTED (expr) |= TREE_PROTECTED (read_expr); + TREE_STATIC (expr) |= TREE_STATIC (read_expr); + TREE_DEPRECATED (expr) |= TREE_DEPRECATED (read_expr); + TREE_VISITED (expr) |= TREE_VISITED (read_expr); + if (TREE_CODE_CLASS (code) == tcc_declaration) + { + if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) + { + DECL_INTERFACE_KNOWN (expr) |= DECL_INTERFACE_KNOWN (read_expr); + } + if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)) + { + DECL_WEAK (expr) |= DECL_WEAK (read_expr); + } + if (code == FUNCTION_DECL) + { + DECL_DECLARED_INLINE_P (expr) |= DECL_DECLARED_INLINE_P (read_expr); + } + } +} + + /* Read a merge key from STREAM. If CHAIN is not NULL and the merge key read from STREAM is not found in *CHAIN, the newly allocated tree is added to it. If no CHAIN is given, then the tree is just @@ -2537,6 +2570,8 @@ pph_in_merge_key_tree (pph_stream *strea the existing tree that matches READ_EXPR. Otherwise, EXPR is the newly allocated READ_EXPR. */ expr = pph_merge_into_chain (read_expr, name, chain); + if (expr != read_expr) + pph_merge_tree_attributes (expr, read_expr); } else { @@ -2609,10 +2644,18 @@ pph_in_tree (pph_stream *stream) if (marker == PPH_RECORD_START_MUTATED) { - /* When reading a mutated tree, we only need to re-read its - body, the tree itself is already in the cache for another - PPH image. */ + tree read_expr; + bool fully_read_p; + /* When reading a mutated tree, the tree itself is already in the + cache for another PPH image. */ expr = (tree) pph_cache_find (stream, marker, image_ix, ix, PPH_any_tree); + read_expr = pph_in_tree_header (stream, &fully_read_p); + /* FIXME pph: We should really merge into the existing tree, + but that requires significant changes to the generic streamer. */ + pph_merge_tree_attributes (expr, read_expr); + ggc_free (read_expr); + if (fully_read_p) + return expr; } else if (marker == PPH_RECORD_START_MERGE_BODY) { -- This patch is available for review at http://codereview.appspot.com/5699055