diff options
author | Richard Henderson <rth@gcc.gnu.org> | 2006-03-09 10:14:39 -0800 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 2006-03-09 10:14:39 -0800 |
commit | 1799e5d5ca20304e32f7d1134ba5e8a2ab231880 (patch) | |
tree | 461ecbd500b6dd4b3b219e43f1580a187a1407cf /gcc/cp/semantics.c | |
parent | f8fe05458d2116e5dcd2aa3eac9dff868be27cfb (diff) | |
download | gcc-1799e5d5ca20304e32f7d1134ba5e8a2ab231880.tar.gz |
Merge C++ from gomp-20050608-branch.
From-SVN: r111867
Diffstat (limited to 'gcc/cp/semantics.c')
-rw-r--r-- | gcc/cp/semantics.c | 615 |
1 files changed, 614 insertions, 1 deletions
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 89d41d66dac..1931dc97f8f 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -743,6 +743,9 @@ finish_return_stmt (tree expr) bool no_warning; expr = check_return_expr (expr, &no_warning); + + if (flag_openmp && !check_omp_return ()) + return error_mark_node; if (!processing_template_decl) { if (DECL_DESTRUCTOR_P (current_function_decl) @@ -3219,9 +3222,619 @@ finalize_nrv (tree *tp, tree var, tree result) walk_tree (tp, finalize_nrv_r, &data, 0); htab_delete (data.visited); } + +/* For all elements of CLAUSES, validate them vs OpenMP constraints. + Remove any elements from the list that are invalid. */ + +tree +finish_omp_clauses (tree clauses) +{ + bitmap_head generic_head, firstprivate_head, lastprivate_head; + tree c, t, *pc = &clauses; + const char *name; + + bitmap_obstack_initialize (NULL); + bitmap_initialize (&generic_head, &bitmap_default_obstack); + bitmap_initialize (&firstprivate_head, &bitmap_default_obstack); + bitmap_initialize (&lastprivate_head, &bitmap_default_obstack); + + for (pc = &clauses, c = clauses; c ; c = *pc) + { + bool remove = false; + + switch (OMP_CLAUSE_CODE (c)) + { + case OMP_CLAUSE_SHARED: + name = "shared"; + goto check_dup_generic; + case OMP_CLAUSE_PRIVATE: + name = "private"; + goto check_dup_generic; + case OMP_CLAUSE_REDUCTION: + name = "reduction"; + goto check_dup_generic; + case OMP_CLAUSE_COPYPRIVATE: + name = "copyprivate"; + goto check_dup_generic; + case OMP_CLAUSE_COPYIN: + name = "copyin"; + goto check_dup_generic; + check_dup_generic: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + if (processing_template_decl) + break; + error ("%qE is not a variable in clause %qs", t, name); + remove = true; + } + else if (bitmap_bit_p (&generic_head, DECL_UID (t)) + || bitmap_bit_p (&firstprivate_head, DECL_UID (t)) + || bitmap_bit_p (&lastprivate_head, DECL_UID (t))) + { + error ("%qE appears more than once in data clauses", t); + remove = true; + } + else + bitmap_set_bit (&generic_head, DECL_UID (t)); + break; + + case OMP_CLAUSE_FIRSTPRIVATE: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + if (processing_template_decl) + break; + error ("%qE is not a variable in clause %<firstprivate%>", t); + remove = true; + } + else if (bitmap_bit_p (&generic_head, DECL_UID (t)) + || bitmap_bit_p (&firstprivate_head, DECL_UID (t))) + { + error ("%qE appears more than once in data clauses", t); + remove = true; + } + else + bitmap_set_bit (&firstprivate_head, DECL_UID (t)); + break; + + case OMP_CLAUSE_LASTPRIVATE: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + if (processing_template_decl) + break; + error ("%qE is not a variable in clause %<lastprivate%>", t); + remove = true; + } + else if (bitmap_bit_p (&generic_head, DECL_UID (t)) + || bitmap_bit_p (&lastprivate_head, DECL_UID (t))) + { + error ("%qE appears more than once in data clauses", t); + remove = true; + } + else + bitmap_set_bit (&lastprivate_head, DECL_UID (t)); + break; + + case OMP_CLAUSE_IF: + t = OMP_CLAUSE_IF_EXPR (c); + t = maybe_convert_cond (t); + if (t == error_mark_node) + remove = true; + OMP_CLAUSE_IF_EXPR (c) = t; + break; + + case OMP_CLAUSE_NUM_THREADS: + t = OMP_CLAUSE_NUM_THREADS_EXPR (c); + if (t == error_mark_node) + remove = true; + else if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) + && !type_dependent_expression_p (t)) + { + error ("num_threads expression must be integral"); + remove = true; + } + break; + + case OMP_CLAUSE_SCHEDULE: + t = OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c); + if (t == NULL) + ; + else if (t == error_mark_node) + remove = true; + else if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) + && !type_dependent_expression_p (t)) + { + error ("schedule chunk size expression must be integral"); + remove = true; + } + break; + + case OMP_CLAUSE_NOWAIT: + case OMP_CLAUSE_ORDERED: + case OMP_CLAUSE_DEFAULT: + break; + + default: + gcc_unreachable (); + } + + if (remove) + *pc = OMP_CLAUSE_CHAIN (c); + else + pc = &OMP_CLAUSE_CHAIN (c); + } + + for (pc = &clauses, c = clauses; c ; c = *pc) + { + enum tree_code c_kind = OMP_CLAUSE_CODE (c); + bool remove = false; + bool need_complete_non_reference = false; + bool need_default_ctor = false; + bool need_copy_ctor = false; + bool need_copy_assignment = false; + bool need_implicitly_determined = false; + tree type, inner_type; + + switch (c_kind) + { + case OMP_CLAUSE_SHARED: + name = "shared"; + need_implicitly_determined = true; + break; + case OMP_CLAUSE_PRIVATE: + name = "private"; + need_complete_non_reference = true; + need_default_ctor = true; + need_implicitly_determined = true; + break; + case OMP_CLAUSE_FIRSTPRIVATE: + name = "firstprivate"; + need_complete_non_reference = true; + need_copy_ctor = true; + need_implicitly_determined = true; + break; + case OMP_CLAUSE_LASTPRIVATE: + name = "lastprivate"; + need_complete_non_reference = true; + need_copy_assignment = true; + need_implicitly_determined = true; + break; + case OMP_CLAUSE_REDUCTION: + name = "reduction"; + need_implicitly_determined = true; + break; + case OMP_CLAUSE_COPYPRIVATE: + name = "copyprivate"; + need_copy_assignment = true; + break; + case OMP_CLAUSE_COPYIN: + name = "copyin"; + need_copy_assignment = true; + break; + default: + pc = &OMP_CLAUSE_CHAIN (c); + continue; + } + + t = OMP_CLAUSE_DECL (c); + if (processing_template_decl + && TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + pc = &OMP_CLAUSE_CHAIN (c); + continue; + } + + switch (c_kind) + { + case OMP_CLAUSE_LASTPRIVATE: + if (!bitmap_bit_p (&firstprivate_head, DECL_UID (t))) + need_default_ctor = true; + break; + + case OMP_CLAUSE_REDUCTION: + if (AGGREGATE_TYPE_P (TREE_TYPE (t)) + || POINTER_TYPE_P (TREE_TYPE (t))) + { + error ("%qE has invalid type for %<reduction%>", t); + remove = true; + } + else if (FLOAT_TYPE_P (TREE_TYPE (t))) + { + enum tree_code r_code = OMP_CLAUSE_REDUCTION_CODE (c); + switch (r_code) + { + case PLUS_EXPR: + case MULT_EXPR: + case MINUS_EXPR: + break; + default: + error ("%qE has invalid type for %<reduction(%s)%>", + t, operator_name_info[r_code].name); + remove = true; + } + } + break; + + case OMP_CLAUSE_COPYIN: + if (TREE_CODE (t) != VAR_DECL || !DECL_THREAD_LOCAL_P (t)) + { + error ("%qE must be %<threadprivate%> for %<copyin%>", t); + remove = true; + } + break; + + default: + break; + } + + if (need_complete_non_reference) + { + t = require_complete_type (t); + if (t == error_mark_node) + remove = true; + else if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE) + { + error ("%qE has reference type for %qs", t, name); + remove = true; + } + } + if (need_implicitly_determined) + { + const char *share_name = NULL; + + if (TREE_CODE (t) == VAR_DECL && DECL_THREAD_LOCAL_P (t)) + share_name = "threadprivate"; + else switch (cxx_omp_predetermined_sharing (t)) + { + case OMP_CLAUSE_DEFAULT_UNSPECIFIED: + break; + case OMP_CLAUSE_DEFAULT_SHARED: + share_name = "shared"; + break; + case OMP_CLAUSE_DEFAULT_PRIVATE: + share_name = "private"; + break; + default: + gcc_unreachable (); + } + if (share_name) + { + error ("%qE is predetermined %qs for %qs", + t, share_name, name); + remove = true; + } + } + + /* We're interested in the base element, not arrays. */ + inner_type = type = TREE_TYPE (t); + while (TREE_CODE (inner_type) == ARRAY_TYPE) + inner_type = TREE_TYPE (inner_type); + + /* Check for special function availablity by building a call to one. + Save the results, because later we won't be in the right context + for making these queries. */ + if (CLASS_TYPE_P (inner_type) + && (need_default_ctor || need_copy_ctor || need_copy_assignment)) + { + int save_errorcount = errorcount; + tree info; + + /* Always allocate 3 elements for simplicity. These are the + function decls for the ctor, dtor, and assignment op. + This layout is known to the three lang hooks, + cxx_omp_clause_default_init, cxx_omp_clause_copy_init, + and cxx_omp_clause_assign_op. */ + info = make_tree_vec (3); + CP_OMP_CLAUSE_INFO (c) = info; + + if (need_default_ctor + || (need_copy_ctor + && !TYPE_HAS_TRIVIAL_INIT_REF (inner_type))) + { + if (need_default_ctor) + t = NULL; + else + { + t = build_int_cst (build_pointer_type (inner_type), 0); + t = build1 (INDIRECT_REF, inner_type, t); + t = build_tree_list (NULL, t); + } + t = build_special_member_call (NULL_TREE, + complete_ctor_identifier, + t, inner_type, LOOKUP_NORMAL); + t = get_callee_fndecl (t); + TREE_VEC_ELT (info, 0) = t; + } + + if ((need_default_ctor || need_copy_ctor) + && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (inner_type)) + { + t = build_int_cst (build_pointer_type (inner_type), 0); + t = build1 (INDIRECT_REF, inner_type, t); + t = build_special_member_call (t, complete_dtor_identifier, + NULL, inner_type, LOOKUP_NORMAL); + t = get_callee_fndecl (t); + TREE_VEC_ELT (info, 1) = t; + } + + if (need_copy_assignment + && !TYPE_HAS_TRIVIAL_ASSIGN_REF (inner_type)) + { + t = build_int_cst (build_pointer_type (inner_type), 0); + t = build1 (INDIRECT_REF, inner_type, t); + t = build_special_member_call (t, ansi_assopname (NOP_EXPR), + build_tree_list (NULL, t), + inner_type, LOOKUP_NORMAL); + + /* We'll have called convert_from_reference on the call, which + may well have added an indirect_ref. It's unneeded here, + and in the way, so kill it. */ + if (TREE_CODE (t) == INDIRECT_REF) + t = TREE_OPERAND (t, 0); + + t = get_callee_fndecl (t); + TREE_VEC_ELT (info, 2) = t; + } + + if (errorcount != save_errorcount) + remove = true; + } + + if (remove) + *pc = OMP_CLAUSE_CHAIN (c); + else + pc = &OMP_CLAUSE_CHAIN (c); + } + + bitmap_obstack_release (NULL); + return clauses; +} + +/* For all variables in the tree_list VARS, mark them as thread local. */ + +void +finish_omp_threadprivate (tree vars) +{ + tree t; + + /* Mark every variable in VARS to be assigned thread local storage. */ + for (t = vars; t; t = TREE_CHAIN (t)) + { + tree v = TREE_PURPOSE (t); + + /* If V had already been marked threadprivate, it doesn't matter + whether it had been used prior to this point. */ + if (TREE_USED (v) + && (DECL_LANG_SPECIFIC (v) == NULL + || !CP_DECL_THREADPRIVATE_P (v))) + error ("%qE declared %<threadprivate%> after first use", v); + else if (! TREE_STATIC (v) && ! DECL_EXTERNAL (v)) + error ("automatic variable %qE cannot be %<threadprivate%>", v); + else if (! COMPLETE_TYPE_P (TREE_TYPE (v))) + error ("%<threadprivate%> %qE has incomplete type", v); + else if (TREE_STATIC (v) && TYPE_P (CP_DECL_CONTEXT (v))) + error ("%<threadprivate%> %qE is not file, namespace " + "or block scope variable", v); + else + { + /* Allocate a LANG_SPECIFIC structure for V, if needed. */ + if (DECL_LANG_SPECIFIC (v) == NULL) + { + retrofit_lang_decl (v); + + /* Make sure that DECL_DISCRIMINATOR_P continues to be true + after the allocation of the lang_decl structure. */ + if (DECL_DISCRIMINATOR_P (v)) + DECL_LANG_SPECIFIC (v)->decl_flags.u2sel = 1; + } + + if (! DECL_THREAD_LOCAL_P (v)) + { + DECL_TLS_MODEL (v) = decl_default_tls_model (v); + /* If rtl has been already set for this var, call + make_decl_rtl once again, so that encode_section_info + has a chance to look at the new decl flags. */ + if (DECL_RTL_SET_P (v)) + make_decl_rtl (v); + } + CP_DECL_THREADPRIVATE_P (v) = 1; + } + } +} + +/* Build an OpenMP structured block. */ + +tree +begin_omp_structured_block (void) +{ + return do_pushlevel (sk_omp); +} + +tree +finish_omp_structured_block (tree block) +{ + return do_poplevel (block); +} + +/* Similarly, except force the retension of the BLOCK. */ + +tree +begin_omp_parallel (void) +{ + keep_next_level (true); + return begin_omp_structured_block (); +} + +tree +finish_omp_parallel (tree clauses, tree body) +{ + tree stmt; + + body = finish_omp_structured_block (body); -/* Perform initialization related to this module. */ + stmt = make_node (OMP_PARALLEL); + TREE_TYPE (stmt) = void_type_node; + OMP_PARALLEL_CLAUSES (stmt) = clauses; + OMP_PARALLEL_BODY (stmt) = body; + return add_stmt (stmt); +} + +/* Build and validate an OMP_FOR statement. CLAUSES, BODY, COND, INCR + are directly for their associated operands in the statement. DECL + and INIT are a combo; if DECL is NULL then INIT ought to be a + MODIFY_EXPR, and the DECL should be extracted. PRE_BODY are + optional statements that need to go before the loop into its + sk_omp scope. */ + +tree +finish_omp_for (location_t locus, tree decl, tree init, tree cond, + tree incr, tree body, tree pre_body) +{ + if (decl == NULL) + { + if (init != NULL) + switch (TREE_CODE (init)) + { + case MODIFY_EXPR: + decl = TREE_OPERAND (init, 0); + init = TREE_OPERAND (init, 1); + break; + case MODOP_EXPR: + if (TREE_CODE (TREE_OPERAND (init, 1)) == NOP_EXPR) + { + decl = TREE_OPERAND (init, 0); + init = TREE_OPERAND (init, 2); + } + break; + default: + break; + } + + if (decl == NULL) + { + error ("expected iteration declaration or initialization"); + return NULL; + } + } + + if (type_dependent_expression_p (decl) + || type_dependent_expression_p (init) + || (cond && type_dependent_expression_p (cond)) + || (incr && type_dependent_expression_p (incr))) + { + tree stmt; + + if (cond == NULL) + { + error ("%Hmissing controlling predicate", &locus); + return NULL; + } + + if (incr == NULL) + { + error ("%Hmissing increment expression", &locus); + return NULL; + } + + stmt = make_node (OMP_FOR); + + /* This is really just a place-holder. We'll be decomposing this + again and going through the build_modify_expr path below when + we instantiate the thing. */ + init = build2 (MODIFY_EXPR, void_type_node, decl, init); + + TREE_TYPE (stmt) = void_type_node; + OMP_FOR_INIT (stmt) = init; + OMP_FOR_COND (stmt) = cond; + OMP_FOR_INCR (stmt) = incr; + OMP_FOR_BODY (stmt) = body; + OMP_FOR_PRE_BODY (stmt) = pre_body; + + SET_EXPR_LOCATION (stmt, locus); + return add_stmt (stmt); + } + + if (!DECL_P (decl)) + { + error ("expected iteration declaration or initialization"); + return NULL; + } + + if (pre_body == NULL || IS_EMPTY_STMT (pre_body)) + pre_body = NULL; + else if (! processing_template_decl) + { + add_stmt (pre_body); + pre_body = NULL; + } + init = build_modify_expr (decl, NOP_EXPR, init); + return c_finish_omp_for (locus, decl, init, cond, incr, body, pre_body); +} + +void +finish_omp_atomic (enum tree_code code, tree lhs, tree rhs) +{ + /* If either of the operands are dependent, we can't do semantic + processing yet. Stuff the values away for now. We cheat a bit + and use the same tree code for this, even though the operands + are of totally different form, thus we need to remember which + statements are which, thus the lang_flag bit. */ + /* ??? We ought to be using type_dependent_expression_p, but the + invocation of build_modify_expr in c_finish_omp_atomic can result + in the creation of CONVERT_EXPRs, which are not handled by + tsubst_copy_and_build. */ + if (uses_template_parms (lhs) || uses_template_parms (rhs)) + { + tree stmt = build2 (OMP_ATOMIC, void_type_node, lhs, rhs); + OMP_ATOMIC_DEPENDENT_P (stmt) = 1; + OMP_ATOMIC_CODE (stmt) = code; + add_stmt (stmt); + } + else + c_finish_omp_atomic (code, lhs, rhs); +} + +void +finish_omp_barrier (void) +{ + tree fn = built_in_decls[BUILT_IN_GOMP_BARRIER]; + tree stmt = finish_call_expr (fn, NULL, false, false); + finish_expr_stmt (stmt); +} + +void +finish_omp_flush (void) +{ + tree fn = built_in_decls[BUILT_IN_SYNCHRONIZE]; + tree stmt = finish_call_expr (fn, NULL, false, false); + finish_expr_stmt (stmt); +} + +/* True if OpenMP sharing attribute of DECL is predetermined. */ + +enum omp_clause_default_kind +cxx_omp_predetermined_sharing (tree decl) +{ + enum omp_clause_default_kind kind; + + kind = c_omp_predetermined_sharing (decl); + if (kind != OMP_CLAUSE_DEFAULT_UNSPECIFIED) + return kind; + + /* Static data members are predetermined as shared. */ + if (TREE_STATIC (decl)) + { + tree ctx = CP_DECL_CONTEXT (decl); + if (TYPE_P (ctx) && IS_AGGR_TYPE (ctx)) + return OMP_CLAUSE_DEFAULT_SHARED; + } + + return OMP_CLAUSE_DEFAULT_UNSPECIFIED; +} + void init_cp_semantics (void) { |