This patch follows on from https://gcc.gnu.org/ml/gcc-patches/2015-12/msg02142.html
As discussed, it creates a separate function cilk_cp_detect_spawn_and_unwrap in gcc/cp to handle processing cilk_spawn expressions for c++ and adds support for implicit constructor and type conversions. Bootstrapped and regression tested on x86_64-linux. gcc/c-family/ChangeLog: 2015-01-20 Ryan Burn <cont...@rnburn.com> PR c++/69024 PR c++/68997 * cilk.c (cilk_ignorable_spawn_rhs_op): Change to have external linkage. * cilk.c (recognize_spawn): Rename to cilk_recognize_spawn. Change to have external linkage. * cilk.c (cilk_detect_and_unwrap): Rename to recognize_spawn to cilk_recognize_spawn. * cilk.c (extract_free_variables): Don't extract free variables from AGGR_INIT_EXPR slot. gcc/cp/ChangeLog 2015-01-20 Ryan Burn <cont...@rnburn.com> PR c++/69024 PR c++/68997 * cp-gimplify.c (cp_gimplify_expr): Call cilk_cp_detect_spawn_and_unwrap instead of cilk_detect_spawn_and_unwrap. * cp-cilkplus.c (is_conversion_operator_function_decl_p): New. * cp-cilkplus.c (find_spawn): New. * cp-cilkplus.c (cilk_cp_detect_spawn_and_unwrap): New. gcc/testsuite/ChangeLog 2015-01-20 Ryan Burn <cont...@rnburn.com> PR c++/69024 PR c++/68997 * g++.dg/cilk-plus/CK/pr68001.cc: Fix to not depend on broken diagnostic. * g++.dg/cilk-plus/CK/pr69024.cc: New test. * g++.dg/cilk-plus/CK/pr68997.cc: New test.
Index: gcc/c-family/cilk.c =================================================================== --- gcc/c-family/cilk.c (revision 232444) +++ gcc/c-family/cilk.c (working copy) @@ -185,7 +185,7 @@ A comparison to constant is simple enough to allow, and is used to convert to bool. */ -static bool +bool cilk_ignorable_spawn_rhs_op (tree exp) { enum tree_code code = TREE_CODE (exp); @@ -223,8 +223,8 @@ /* Returns true when EXP is a CALL_EXPR with _Cilk_spawn in front. Unwraps CILK_SPAWN_STMT wrapper from the CALL_EXPR in *EXP0 statement. */ -static bool -recognize_spawn (tree exp, tree *exp0) +bool +cilk_recognize_spawn (tree exp, tree *exp0) { bool spawn_found = false; if (TREE_CODE (exp) == CILK_SPAWN_STMT) @@ -292,7 +292,7 @@ /* Now we should have a CALL_EXPR with a CILK_SPAWN_STMT wrapper around it, or return false. */ - if (recognize_spawn (exp, exp0)) + if (cilk_recognize_spawn (exp, exp0)) return true; return false; } @@ -1251,6 +1251,21 @@ return; case AGGR_INIT_EXPR: + { + int len = 0; + int ii = 0; + extract_free_variables (TREE_OPERAND (t, 1), wd, ADD_READ); + if (TREE_CODE (TREE_OPERAND (t, 0)) == INTEGER_CST) + { + len = TREE_INT_CST_LOW (TREE_OPERAND (t, 0)); + + for (ii = 3; ii < len; ii++) + extract_free_variables (TREE_OPERAND (t, ii), wd, ADD_READ); + extract_free_variables (TREE_TYPE (t), wd, ADD_READ); + } + break; + } + case CALL_EXPR: { int len = 0; Index: gcc/cp/cp-gimplify.c =================================================================== --- gcc/cp/cp-gimplify.c (revision 232444) +++ gcc/cp/cp-gimplify.c (working copy) @@ -39,6 +39,7 @@ static tree cp_fold_r (tree *, int *, void *); static void cp_genericize_tree (tree*); static tree cp_fold (tree); +bool cilk_cp_detect_spawn_and_unwrap (tree *); /* Local declarations. */ @@ -619,7 +620,7 @@ case INIT_EXPR: if (fn_contains_cilk_spawn_p (cfun)) { - if (cilk_detect_spawn_and_unwrap (expr_p)) + if (cilk_cp_detect_spawn_and_unwrap (expr_p)) { cilk_cp_gimplify_call_params_in_spawned_fn (expr_p, pre_p, post_p); @@ -637,7 +638,7 @@ modify_expr_case: { if (fn_contains_cilk_spawn_p (cfun) - && cilk_detect_spawn_and_unwrap (expr_p) + && cilk_cp_detect_spawn_and_unwrap (expr_p) && !seen_error ()) { cilk_cp_gimplify_call_params_in_spawned_fn (expr_p, pre_p, post_p); @@ -738,7 +739,7 @@ case CILK_SPAWN_STMT: gcc_assert(fn_contains_cilk_spawn_p (cfun) - && cilk_detect_spawn_and_unwrap (expr_p)); + && cilk_cp_detect_spawn_and_unwrap (expr_p)); if (!seen_error ()) { @@ -749,7 +750,7 @@ case CALL_EXPR: if (fn_contains_cilk_spawn_p (cfun) - && cilk_detect_spawn_and_unwrap (expr_p) + && cilk_cp_detect_spawn_and_unwrap (expr_p) && !seen_error ()) { cilk_cp_gimplify_call_params_in_spawned_fn (expr_p, pre_p, post_p); Index: gcc/cp/cp-cilkplus.c =================================================================== --- gcc/cp/cp-cilkplus.c (revision 232444) +++ gcc/cp/cp-cilkplus.c (working copy) @@ -27,6 +27,108 @@ #include "tree-iterator.h" #include "cilk.h" +bool cilk_ignorable_spawn_rhs_op (tree); +bool cilk_recognize_spawn (tree, tree *); + +/* Return TRUE if T is a FUNCTION_DECL for a type-conversion operator. */ + +static bool +is_conversion_operator_function_decl_p (tree t) { + if (TREE_CODE (t) != FUNCTION_DECL) + return false; + + return DECL_NAME (t) && IDENTIFIER_TYPENAME_P (DECL_NAME (t)); +} + +/* Recursively traverse EXP to search for a CILK_SPAWN_STMT subtree. Return the + CILK_SPAWN_STMT subtree if found; otherwise, the last subtree searched. */ + +static tree +find_spawn (tree exp) +{ + /* Happens with C++ TARGET_EXPR. */ + if (exp == NULL_TREE) + return exp; + + if (cilk_ignorable_spawn_rhs_op (exp)) + return find_spawn (TREE_OPERAND (exp, 0)); + + switch (TREE_CODE (exp)) + { + case AGGR_INIT_EXPR: + { + /* Check for initialization via a constructor call that represents + implicit conversion. */ + if (AGGR_INIT_VIA_CTOR_P (exp) && aggr_init_expr_nargs (exp) == 2) + return find_spawn (AGGR_INIT_EXPR_ARG (exp, 1)); + + /* Check for initialization via a call to a type-conversion + operator. */ + tree fn = AGGR_INIT_EXPR_FN (exp); + if (TREE_CODE (fn) == ADDR_EXPR + && is_conversion_operator_function_decl_p (TREE_OPERAND (fn, 0)) + && aggr_init_expr_nargs (exp) == 1) + return find_spawn (AGGR_INIT_EXPR_ARG (exp, 0)); + } + break; + + case CALL_EXPR: + { + /* Check for a call to a type-conversion operator. */ + tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); + if (is_conversion_operator_function_decl_p (fndecl) + && call_expr_nargs (exp) == 1) + return find_spawn (CALL_EXPR_ARG (exp, 0)); + } + break; + + case TARGET_EXPR: + return find_spawn (TARGET_EXPR_INITIAL (exp)); + + case CLEANUP_POINT_EXPR: + case COMPOUND_EXPR: + case EXPR_STMT: + return find_spawn (TREE_OPERAND (exp, 0)); + + default: + break; + } + + return exp; +} + +/* Returns true if *EXP0 is a recognized form of spawn. Recognized forms are, + after conversion to void, a call expression at outer level or an assignment + at outer level with the right hand side being a spawned call. + In addition to this, it also unwraps the CILK_SPAWN_STMT cover from the + CALL_EXPR that is being spawned. + Note that `=' in C++ may turn into a CALL_EXPR rather than a MODIFY_EXPR. */ + +bool +cilk_cp_detect_spawn_and_unwrap (tree *exp0) +{ + tree exp = *exp0; + + if (!TREE_SIDE_EFFECTS (exp)) + return false; + + /* Strip off any conversion to void. It does not affect whether spawn + is supported here. */ + if (TREE_CODE (exp) == CONVERT_EXPR && VOID_TYPE_P (TREE_TYPE (exp))) + exp = TREE_OPERAND (exp, 0); + + if (TREE_CODE (exp) == MODIFY_EXPR || TREE_CODE (exp) == INIT_EXPR) + exp = TREE_OPERAND (exp, 1); + + exp = find_spawn (exp); + if (exp == NULL_TREE) + return false; + + /* Now we should have a CALL_EXPR with a CILK_SPAWN_STMT wrapper around + it, or return false. */ + return cilk_recognize_spawn (exp, exp0); +} + /* Callback for cp_walk_tree to validate the body of a pragma simd loop or _cilk_for loop. Index: gcc/testsuite/g++.dg/cilk-plus/CK/pr68001.cc =================================================================== --- gcc/testsuite/g++.dg/cilk-plus/CK/pr68001.cc (revision 232444) +++ gcc/testsuite/g++.dg/cilk-plus/CK/pr68001.cc (working copy) @@ -11,7 +11,7 @@ int main() { - std::vector<double> x = _Cilk_spawn f(); /* { dg-error "invalid use of" } */ + std::vector<double> x = _Cilk_spawn f (); std::vector<double> y = f(); _Cilk_sync; return 0; Index: gcc/testsuite/g++.dg/cilk-plus/CK/pr69024.cc =================================================================== --- gcc/testsuite/g++.dg/cilk-plus/CK/pr69024.cc (revision 0) +++ gcc/testsuite/g++.dg/cilk-plus/CK/pr69024.cc (working copy) @@ -0,0 +1,38 @@ +/* { dg-do compile } */ +/* { dg-options "-fcilkplus" } */ + +struct A1 { +}; + +struct A2 { + A2 () {} + A2 (const A2&) {} +}; + +struct B1 { + operator A1 () { + return A1 (); + } +}; + +B1 fb1 () { + return B1 (); +} + +struct B2 { + operator A2 () { + return A2 (); + } +}; + +B2 fb2 () { + return B2 (); +} + +void t1 () { + A1 a1 = _Cilk_spawn fb1 (); +} + +void t2 () { + A2 a2 = _Cilk_spawn fb2 (); +} Index: gcc/testsuite/g++.dg/cilk-plus/CK/pr68997.cc =================================================================== --- gcc/testsuite/g++.dg/cilk-plus/CK/pr68997.cc (revision 0) +++ gcc/testsuite/g++.dg/cilk-plus/CK/pr68997.cc (working copy) @@ -0,0 +1,68 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c++11 -fcilkplus" } */ + +struct A1 { + A1 () {} + A1 (const A1&) {} +}; + +A1 fa1 () { + return A1 (); +} + +struct A2 { + A2 () {} + A2 (A2&&) {} +}; + +A2 fa2 () { + A2 (); +} + +struct B1 { +}; + +B1 fb1 () { + return B1 (); +} + +struct A3 { + A3 (const B1&) {} +}; + +struct A4 { + A4 (B1) {} +}; + +struct B2 { + B2 () {} + B2 (const B2&) {} +}; + +B2 fb2 () { + return B2 (); +} + +struct A5 { + A5 (B2) {} +}; + +void t1 () { + A1 a1 = _Cilk_spawn fa1 (); +} + +void t2 () { + A2 a2 = _Cilk_spawn fa2 (); +} + +void t3 () { + A3 a3 = _Cilk_spawn fb1 (); +} + +void t4 () { + A4 a4 = _Cilk_spawn fb1 (); +} + +void t5 () { + A5 a5 = _Cilk_spawn fb2 (); +}