From 10827cd8b31a8ced2cf6fbd6e4b902628c9a4ceb Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 13 Jun 2006 11:21:30 +0200 Subject: [PATCH] re PR middle-end/27793 (num_ssa_names inconsistent or immediate use iterator wrong) PR middle-end/27793 * cp-tree.h (cxx_int_tree_map): New struct. (struct language_function): Add extern_decl_map field. * name-lookup.c (pushdecl_maybe_friend): Add x -> t mapping to cp_function_chain->extern_decl_map hash table instead of copying over DECL_UID. * cp-gimplify.c (cxx_int_tree_map_eq, cxx_int_tree_map_hash): New functions. (cp_genericize_r): Remap DECL_EXTERN local decls using cp_function_chain->extern_decl_map hash table. * decl.c (finish_function): Clear extern_decl_map. PR c++/26757 PR c++/27894 * g++.dg/tree-ssa/pr26757.C: New test. * g++.dg/tree-ssa/pr27894.C: New test. From-SVN: r114607 --- gcc/cp/ChangeLog | 14 +++++ gcc/cp/cp-gimplify.c | 37 +++++++++++ gcc/cp/cp-tree.h | 10 +++ gcc/cp/decl.c | 1 + gcc/cp/name-lookup.c | 26 ++++++-- gcc/testsuite/ChangeLog | 6 ++ gcc/testsuite/g++.dg/tree-ssa/pr26757.C | 44 +++++++++++++ gcc/testsuite/g++.dg/tree-ssa/pr27894.C | 82 +++++++++++++++++++++++++ 8 files changed, 214 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/g++.dg/tree-ssa/pr26757.C create mode 100644 gcc/testsuite/g++.dg/tree-ssa/pr27894.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f64c233c4e7..129f5df0deb 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,17 @@ +2006-06-13 Jakub Jelinek + + PR middle-end/27793 + * cp-tree.h (cxx_int_tree_map): New struct. + (struct language_function): Add extern_decl_map field. + * name-lookup.c (pushdecl_maybe_friend): Add x -> t mapping + to cp_function_chain->extern_decl_map hash table instead of + copying over DECL_UID. + * cp-gimplify.c (cxx_int_tree_map_eq, cxx_int_tree_map_hash): New + functions. + (cp_genericize_r): Remap DECL_EXTERN local decls using + cp_function_chain->extern_decl_map hash table. + * decl.c (finish_function): Clear extern_decl_map. + 2006-06-12 Volker Reichelt PR c++/27601 diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 7ded34fb696..ca8ff5fcfde 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -601,6 +601,24 @@ is_invisiref_parm (tree t) && DECL_BY_REFERENCE (t)); } +/* Return true if the uid in both int tree maps are equal. */ + +int +cxx_int_tree_map_eq (const void *va, const void *vb) +{ + const struct cxx_int_tree_map *a = (const struct cxx_int_tree_map *) va; + const struct cxx_int_tree_map *b = (const struct cxx_int_tree_map *) vb; + return (a->uid == b->uid); +} + +/* Hash a UID in a cxx_int_tree_map. */ + +unsigned int +cxx_int_tree_map_hash (const void *item) +{ + return ((const struct cxx_int_tree_map *)item)->uid; +} + /* Perform any pre-gimplification lowering of C++ front end trees to GENERIC. */ @@ -620,6 +638,25 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) return NULL; } + /* Map block scope extern declarations to visible declarations with the + same name and type in outer scopes if any. */ + if (cp_function_chain->extern_decl_map + && (TREE_CODE (stmt) == FUNCTION_DECL || TREE_CODE (stmt) == VAR_DECL) + && DECL_EXTERNAL (stmt)) + { + struct cxx_int_tree_map *h, in; + in.uid = DECL_UID (stmt); + h = (struct cxx_int_tree_map *) + htab_find_with_hash (cp_function_chain->extern_decl_map, + &in, in.uid); + if (h) + { + *stmt_p = h->to; + *walk_subtrees = 0; + return NULL; + } + } + /* Other than invisiref parms, don't walk the same tree twice. */ if (pointer_set_contains (p_set, stmt)) { diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 77b906729eb..c0897a07f73 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -721,6 +721,15 @@ struct saved_scope GTY(()) extern GTY(()) struct saved_scope *scope_chain; +struct cxx_int_tree_map GTY(()) +{ + unsigned int uid; + tree to; +}; + +extern unsigned int cxx_int_tree_map_hash (const void *); +extern int cxx_int_tree_map_eq (const void *, const void *); + /* Global state pertinent to the current function. */ struct language_function GTY(()) @@ -747,6 +756,7 @@ struct language_function GTY(()) htab_t GTY((param_is(struct named_label_entry))) x_named_labels; struct cp_binding_level *bindings; VEC(tree,gc) *x_local_names; + htab_t GTY((param_is (struct cxx_int_tree_map))) extern_decl_map; }; /* The current C++-specific per-function global variables. */ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index eb289d6ab32..206fced6b39 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -11102,6 +11102,7 @@ finish_function (int flags) f->x_vtt_parm = NULL; f->x_return_value = NULL; f->bindings = NULL; + f->extern_decl_map = NULL; /* Handle attribute((warn_unused_result)). Relies on gimple input. */ c_warn_unused_result (&DECL_SAVED_TREE (fndecl)); diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 187a41f5a9f..3de99992a12 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -670,14 +670,28 @@ pushdecl_maybe_friend (tree x, bool is_friend) if (decls_match (x, t)) /* The standard only says that the local extern inherits linkage from the previous decl; in - particular, default args are not shared. We must - also tell cgraph to treat these decls as the same, - or we may neglect to emit an "unused" static - we - do this by making the DECL_UIDs equal, which should - be viewed as a kludge. FIXME. */ + particular, default args are not shared. Add + the decl into a hash table to make sure only + the previous decl in this case is seen by the + middle end. */ { + struct cxx_int_tree_map *h; + void **loc; + TREE_PUBLIC (x) = TREE_PUBLIC (t); - DECL_UID (x) = DECL_UID (t); + + if (cp_function_chain->extern_decl_map == NULL) + cp_function_chain->extern_decl_map + = htab_create_ggc (20, cxx_int_tree_map_hash, + cxx_int_tree_map_eq, NULL); + + h = GGC_NEW (struct cxx_int_tree_map); + h->uid = DECL_UID (x); + h->to = t; + loc = htab_find_slot_with_hash + (cp_function_chain->extern_decl_map, h, + h->uid, INSERT); + *(struct cxx_int_tree_map **) loc = h; } } else if (TREE_CODE (t) == PARM_DECL) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 04c639aea2a..9371ad6ff04 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2006-06-13 Jakub Jelinek + + PR c++/27894 + * g++.dg/tree-ssa/pr26757.C: New test. + * g++.dg/tree-ssa/pr27894.C: New test. + 2006-06-13 Maxim Kuvyrkov * gcc.c-torture/compile/20060609-1.c: New test. diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr26757.C b/gcc/testsuite/g++.dg/tree-ssa/pr26757.C new file mode 100644 index 00000000000..4d124e3c45d --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/pr26757.C @@ -0,0 +1,44 @@ +// PR c++/26757 +// { dg-do run } +// { dg-options "-O" } + +extern "C" void abort (); + +typedef struct A +{ + int c; + int d; +} A; + +A *b; + +void +foo () +{ + b->c++; + extern A *b; + b->d++; + +} + +void +bar () +{ + if (b->d) + b->c++; +} + + +int +main () +{ + A a = { 0, 0 }; + b = &a; + foo (); + bar (); + if (b->c != 2) + abort (); + if (b->d != 1) + abort (); + return 0; +} diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr27894.C b/gcc/testsuite/g++.dg/tree-ssa/pr27894.C new file mode 100644 index 00000000000..ac97a35f1cf --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/pr27894.C @@ -0,0 +1,82 @@ +// PR c++/27894 +// { dg-do compile } +// { dg-options "-O" } + +class A; +struct B +{ + B (unsigned long); + int b2 () const; + A *b1 () const; +}; + +enum { P = 0 }; +enum O { Q = 75, }; +class C; +struct D { A *d; }; +struct E +{ + B e1 (int) const; + A *e2 (const B &) const; + D e3[4096]; +}; + +inline A * +E::e2 (const B & x) const +{ + const D *w = &e3[x.b2 ()]; + return (A *) w->d; +} + +extern E *e; + +inline A * +B::b1 () const +{ + extern E *e; + return e->e2 (*this); +} + +template struct F : public B +{ + F (const B &); + T *b1 () const; +}; + +template < class T > inline T * F ::b1 () const +{ + return (T *) B::b1 (); +}; + +typedef F N; + +class G {}; +class H : public G {}; +class I : public H {}; +class J {}; +class K {}; +struct L +{ + void l (J *, C *, int, const char *, O); +}; +class M : public K, public I +{ + void m (J &, int, const char *); + void m (J &, int, int, const char *, float); +}; + +void +M::m (J &x, int y, const char *z) +{ + L *w = new L; + N v = e->e1 (y); + w->l (&x, v.b1 (), P, z, Q); +} + +void +M::m (J &x, int y, int s, const char *z, float t) +{ + L *w = new L; + N v = e->e1 (y); + w->l (&x, v.b1 (), s, z, (O) (int) ((t) ? (50 + 20 / (float) t) : 0)); +}