2008-09-03 Jakub Jelinek PR c++/37189 * cp-tree.h (defer_mark_used_calls, deferred_mark_used_calls): New extern decls. * decl2.c (mark_used): If defer_mark_used_calls, push decl into deferred_mark_used_calls vector and exit early. * decl.c (defer_mark_used_calls, deferred_mark_used_calls): New variables. (finish_function): Set defer_mark_used_calls for the duration of the function. Call mark_used on any queued decls. PR c++/37189 * g++.dg/gomp/pr37189.C: New test. --- gcc/cp/decl2.c (revision 139954) +++ gcc/cp/decl2.c (revision 139955) @@ -3776,6 +3776,15 @@ mark_used (tree decl) /* If we don't need a value, then we don't need to synthesize DECL. */ if (skip_evaluation) return; + + /* If within finish_function, defer the rest until that function + finishes, otherwise it might recurse. */ + if (defer_mark_used_calls) + { + VEC_safe_push (tree, gc, deferred_mark_used_calls, decl); + return; + } + /* Normally, we can wait until instantiation-time to synthesize DECL. However, if DECL is a static data member initialized with a constant, we need the value right now because a reference to --- gcc/cp/decl.c (revision 139954) +++ gcc/cp/decl.c (revision 139955) @@ -227,6 +227,11 @@ struct named_label_entry GTY(()) function, two inside the body of a function in a local class, etc.) */ int function_depth; +/* To avoid unwanted recursion, finish_function defers all mark_used calls + encountered during its execution until it finishes. */ +bool defer_mark_used_calls; +VEC(tree, gc) *deferred_mark_used_calls; + /* States indicating how grokdeclarator() should handle declspecs marked with __attribute__((deprecated)). An object declared as __attribute__((deprecated)) suppresses warnings of uses of other @@ -12033,6 +12038,9 @@ finish_function (int flags) if (fndecl == NULL_TREE) return error_mark_node; + gcc_assert (!defer_mark_used_calls); + defer_mark_used_calls = true; + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl) && DECL_VIRTUAL_P (fndecl) && !processing_template_decl) @@ -12232,6 +12240,17 @@ finish_function (int flags) cxx_pop_function_context and then reset via pop_function_context. */ current_function_decl = NULL_TREE; + defer_mark_used_calls = false; + if (deferred_mark_used_calls) + { + unsigned int i; + tree decl; + + for (i = 0; VEC_iterate (tree, deferred_mark_used_calls, i, decl); i++) + mark_used (decl); + VEC_free (tree, gc, deferred_mark_used_calls); + } + return fndecl; } --- gcc/cp/cp-tree.h (revision 139954) +++ gcc/cp/cp-tree.h (revision 139955) @@ -4381,6 +4381,9 @@ extern void initialize_artificial_var ( extern tree check_var_type (tree, tree); extern tree reshape_init (tree, tree); +extern bool defer_mark_used_calls; +extern GTY(()) VEC(tree, gc) *deferred_mark_used_calls; + /* in decl2.c */ extern bool check_java_method (tree); extern tree build_memfn_type (tree, tree, cp_cv_quals); --- gcc/testsuite/g++.dg/gomp/pr37189.C (revision 0) +++ gcc/testsuite/g++.dg/gomp/pr37189.C (revision 139955) @@ -0,0 +1,27 @@ +// PR c++/37189 +// { dg-do compile } +// { dg-options "-fopenmp" } + +struct S +{ + S () {} + S (S const &) {} +}; + +struct T +{ + S s; +}; + +void +bar (T &) +{ +} + +int +foo () +{ + T t; + #pragma omp task + bar (t); +}