https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70847
--- Comment #12 from Jakub Jelinek <jakub at gcc dot gnu.org> --- I had in mind: --- cp-gimplify.c.jj1 2016-06-02 18:35:18.000000000 +0200 +++ cp-gimplify.c 2016-06-03 15:06:04.465913964 +0200 @@ -941,13 +941,25 @@ cp_fold_r (tree *stmt_p, int *walk_subtr *stmt_p = stmt = cp_fold (*stmt_p); code = TREE_CODE (stmt); - if (code == OMP_FOR || code == OMP_SIMD || code == OMP_DISTRIBUTE - || code == OMP_TASKLOOP || code == CILK_FOR || code == CILK_SIMD - || code == OACC_LOOP) + switch (code) { tree x; int i, n; + case SAVE_EXPR: + case TARGET_EXPR: + /* For SAVE_EXPR and TARGET_EXPR, only work subtrees once, + otherwise the walking can be exponential. */ + if (((hash_set<tree> *) data)->add (stmt)) + *walk_subtrees = 0; + break; + case OMP_FOR: + case OMP_SIMD: + case OMP_DISTRIBUTE: + case OMP_TASKLOOP: + case CILK_FOR: + case CILK_SIMD: + case OACC_LOOP: cp_walk_tree (&OMP_FOR_BODY (stmt), cp_fold_r, data, NULL); cp_walk_tree (&OMP_FOR_CLAUSES (stmt), cp_fold_r, data, NULL); cp_walk_tree (&OMP_FOR_INIT (stmt), cp_fold_r, data, NULL); @@ -986,6 +998,9 @@ cp_fold_r (tree *stmt_p, int *walk_subtr } cp_walk_tree (&OMP_FOR_PRE_BODY (stmt), cp_fold_r, data, NULL); *walk_subtrees = 0; + break; + default: + break; } return NULL; @@ -997,7 +1012,8 @@ cp_fold_r (tree *stmt_p, int *walk_subtr void cp_fold_function (tree fndecl) { - cp_walk_tree (&DECL_SAVED_TREE (fndecl), cp_fold_r, NULL, NULL); + hash_set<tree> pset; + cp_walk_tree (&DECL_SAVED_TREE (fndecl), cp_fold_r, &pset, NULL); } /* Perform any pre-gimplification lowering of C++ front end trees to which also fixes the testcases. But, you're right, unless something clears the fold cache from within inside cp_fold_function, it should be fine. There is also the question whether we couldn't just use the fold_cache instead of a separate pset; but if it is possible cp_fold has been called before on some subtrees, some tree might be in the cache even when its subtrees weren't walked yet.