From 8487df4052540360ffcdb4a4d82a4b4223398827 Mon Sep 17 00:00:00 2001 From: rth Date: Thu, 9 Mar 2006 18:14:39 +0000 Subject: [PATCH] Merge C++ from gomp-20050608-branch. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@111867 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 5 + gcc/cp/ChangeLog | 497 +++++++++- gcc/cp/Make-lang.in | 2 +- gcc/cp/cp-gimplify.c | 225 ++++- gcc/cp/cp-objcp-common.h | 10 + gcc/cp/cp-tree.h | 51 +- gcc/cp/decl.c | 572 ++++++----- gcc/cp/name-lookup.c | 1 + gcc/cp/name-lookup.h | 5 +- gcc/cp/parser.c | 1428 +++++++++++++++++++++++++-- gcc/cp/pt.c | 119 +++ gcc/cp/semantics.c | 615 +++++++++++- gcc/testsuite/ChangeLog | 5 + gcc/testsuite/g++.dg/dg.exp | 1 + gcc/testsuite/g++.dg/gomp/atomic-1.C | 99 ++ gcc/testsuite/g++.dg/gomp/atomic-2.C | 23 + gcc/testsuite/g++.dg/gomp/atomic-3.C | 13 + gcc/testsuite/g++.dg/gomp/atomic-4.C | 24 + gcc/testsuite/g++.dg/gomp/atomic-5.C | 34 + gcc/testsuite/g++.dg/gomp/atomic-6.C | 11 + gcc/testsuite/g++.dg/gomp/atomic-7.C | 23 + gcc/testsuite/g++.dg/gomp/atomic-8.C | 21 + gcc/testsuite/g++.dg/gomp/atomic-9.C | 13 + gcc/testsuite/g++.dg/gomp/barrier-1.C | 18 + gcc/testsuite/g++.dg/gomp/barrier-2.C | 12 + gcc/testsuite/g++.dg/gomp/block-0.C | 33 + gcc/testsuite/g++.dg/gomp/block-1.C | 22 + gcc/testsuite/g++.dg/gomp/block-10.C | 40 + gcc/testsuite/g++.dg/gomp/block-11.C | 19 + gcc/testsuite/g++.dg/gomp/block-2.C | 32 + gcc/testsuite/g++.dg/gomp/block-3.C | 57 ++ gcc/testsuite/g++.dg/gomp/block-4.C | 9 + gcc/testsuite/g++.dg/gomp/block-5.C | 15 + gcc/testsuite/g++.dg/gomp/block-6.C | 9 + gcc/testsuite/g++.dg/gomp/block-7.C | 20 + gcc/testsuite/g++.dg/gomp/block-8.C | 11 + gcc/testsuite/g++.dg/gomp/block-9.C | 25 + gcc/testsuite/g++.dg/gomp/clause-1.C | 32 + gcc/testsuite/g++.dg/gomp/clause-2.C | 38 + gcc/testsuite/g++.dg/gomp/clause-3.C | 94 ++ gcc/testsuite/g++.dg/gomp/copyin-1.C | 27 + gcc/testsuite/g++.dg/gomp/critical-1.C | 28 + gcc/testsuite/g++.dg/gomp/critical-2.C | 12 + gcc/testsuite/g++.dg/gomp/flush-1.C | 25 + gcc/testsuite/g++.dg/gomp/flush-2.C | 10 + gcc/testsuite/g++.dg/gomp/for-1.C | 49 + gcc/testsuite/g++.dg/gomp/for-10.C | 17 + gcc/testsuite/g++.dg/gomp/for-11.C | 14 + gcc/testsuite/g++.dg/gomp/for-12.C | 12 + gcc/testsuite/g++.dg/gomp/for-13.C | 18 + gcc/testsuite/g++.dg/gomp/for-14.C | 19 + gcc/testsuite/g++.dg/gomp/for-15.C | 35 + gcc/testsuite/g++.dg/gomp/for-16.C | 33 + gcc/testsuite/g++.dg/gomp/for-17.C | 11 + gcc/testsuite/g++.dg/gomp/for-18.C | 67 ++ gcc/testsuite/g++.dg/gomp/for-2.C | 18 + gcc/testsuite/g++.dg/gomp/for-3.C | 62 ++ gcc/testsuite/g++.dg/gomp/for-4.C | 17 + gcc/testsuite/g++.dg/gomp/for-5.C | 17 + gcc/testsuite/g++.dg/gomp/for-6.C | 17 + gcc/testsuite/g++.dg/gomp/for-7.C | 17 + gcc/testsuite/g++.dg/gomp/for-8.C | 17 + gcc/testsuite/g++.dg/gomp/for-9.C | 17 + gcc/testsuite/g++.dg/gomp/gomp.exp | 11 + gcc/testsuite/g++.dg/gomp/macro-1.C | 10 + gcc/testsuite/g++.dg/gomp/macro-2.C | 14 + gcc/testsuite/g++.dg/gomp/master-1.C | 22 + gcc/testsuite/g++.dg/gomp/master-2.C | 7 + gcc/testsuite/g++.dg/gomp/master-3.C | 13 + gcc/testsuite/g++.dg/gomp/method-1.C | 18 + gcc/testsuite/g++.dg/gomp/ordered-1.C | 20 + gcc/testsuite/g++.dg/gomp/ordered-2.C | 7 + gcc/testsuite/g++.dg/gomp/parallel-1.C | 17 + gcc/testsuite/g++.dg/gomp/parallel-2.C | 17 + gcc/testsuite/g++.dg/gomp/parallel-3.C | 15 + gcc/testsuite/g++.dg/gomp/parallel-4.C | 24 + gcc/testsuite/g++.dg/gomp/parallel-5.C | 11 + gcc/testsuite/g++.dg/gomp/pr24849.C | 19 + gcc/testsuite/g++.dg/gomp/pr25874.C | 23 + gcc/testsuite/g++.dg/gomp/sections-1.C | 39 + gcc/testsuite/g++.dg/gomp/sections-2.C | 29 + gcc/testsuite/g++.dg/gomp/sections-3.C | 15 + gcc/testsuite/g++.dg/gomp/sections-4.C | 13 + gcc/testsuite/g++.dg/gomp/sharing-1.C | 77 ++ gcc/testsuite/g++.dg/gomp/tls-1.C | 18 + gcc/testsuite/g++.dg/gomp/tls-2.C | 13 + gcc/testsuite/g++.dg/gomp/tls-3.C | 25 + gcc/testsuite/g++.dg/gomp/tpl-atomic-1.C | 26 + gcc/testsuite/g++.dg/gomp/tpl-atomic-2.C | 41 + gcc/testsuite/g++.dg/gomp/tpl-barrier-1.C | 25 + gcc/testsuite/g++.dg/gomp/tpl-for-1.C | 17 + gcc/testsuite/g++.dg/gomp/tpl-for-2.C | 15 + gcc/testsuite/g++.dg/gomp/tpl-for-3.C | 28 + gcc/testsuite/g++.dg/gomp/tpl-master-1.C | 30 + gcc/testsuite/g++.dg/gomp/tpl-parallel-1.C | 24 + gcc/testsuite/g++.dg/gomp/tpl-parallel-2.C | 20 + gcc/tree-cfg.c | 2 + libgomp/ChangeLog | 4 + libgomp/testsuite/libgomp.c++/c++.exp | 20 + libgomp/testsuite/libgomp.c++/copyin-1.C | 34 + libgomp/testsuite/libgomp.c++/copyin-2.C | 34 + libgomp/testsuite/libgomp.c++/ctor-1.C | 65 ++ libgomp/testsuite/libgomp.c++/ctor-2.C | 76 ++ libgomp/testsuite/libgomp.c++/ctor-3.C | 89 ++ libgomp/testsuite/libgomp.c++/ctor-4.C | 90 ++ libgomp/testsuite/libgomp.c++/ctor-5.C | 52 + libgomp/testsuite/libgomp.c++/ctor-6.C | 50 + libgomp/testsuite/libgomp.c++/ctor-7.C | 67 ++ libgomp/testsuite/libgomp.c++/ctor-8.C | 77 ++ libgomp/testsuite/libgomp.c++/ctor-9.C | 60 ++ libgomp/testsuite/libgomp.c++/loop-1.C | 96 ++ libgomp/testsuite/libgomp.c++/loop-2.C | 32 + libgomp/testsuite/libgomp.c++/loop-3.C | 26 + libgomp/testsuite/libgomp.c++/loop-4.C | 20 + libgomp/testsuite/libgomp.c++/loop-5.C | 19 + libgomp/testsuite/libgomp.c++/loop-6.C | 24 + libgomp/testsuite/libgomp.c++/loop-7.C | 22 + libgomp/testsuite/libgomp.c++/master-1.C | 24 + libgomp/testsuite/libgomp.c++/nested-1.C | 28 + libgomp/testsuite/libgomp.c++/parallel-1.C | 40 + libgomp/testsuite/libgomp.c++/pr24455-1.C | 6 + libgomp/testsuite/libgomp.c++/pr24455.C | 23 + libgomp/testsuite/libgomp.c++/reduction-1.C | 36 + libgomp/testsuite/libgomp.c++/reduction-2.C | 50 + libgomp/testsuite/libgomp.c++/reduction-3.C | 51 + libgomp/testsuite/libgomp.c++/sections-1.C | 64 ++ libgomp/testsuite/libgomp.c++/shared-1.C | 60 ++ libgomp/testsuite/libgomp.c++/shared-2.C | 47 + libgomp/testsuite/libgomp.c++/single-1.C | 19 + libgomp/testsuite/libgomp.c++/single-2.C | 36 + libgomp/testsuite/libgomp.c++/single-3.C | 21 + 131 files changed, 6653 insertions(+), 356 deletions(-) create mode 100644 gcc/testsuite/g++.dg/gomp/atomic-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/atomic-2.C create mode 100644 gcc/testsuite/g++.dg/gomp/atomic-3.C create mode 100644 gcc/testsuite/g++.dg/gomp/atomic-4.C create mode 100644 gcc/testsuite/g++.dg/gomp/atomic-5.C create mode 100644 gcc/testsuite/g++.dg/gomp/atomic-6.C create mode 100644 gcc/testsuite/g++.dg/gomp/atomic-7.C create mode 100644 gcc/testsuite/g++.dg/gomp/atomic-8.C create mode 100644 gcc/testsuite/g++.dg/gomp/atomic-9.C create mode 100644 gcc/testsuite/g++.dg/gomp/barrier-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/barrier-2.C create mode 100644 gcc/testsuite/g++.dg/gomp/block-0.C create mode 100644 gcc/testsuite/g++.dg/gomp/block-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/block-10.C create mode 100644 gcc/testsuite/g++.dg/gomp/block-11.C create mode 100644 gcc/testsuite/g++.dg/gomp/block-2.C create mode 100644 gcc/testsuite/g++.dg/gomp/block-3.C create mode 100644 gcc/testsuite/g++.dg/gomp/block-4.C create mode 100644 gcc/testsuite/g++.dg/gomp/block-5.C create mode 100644 gcc/testsuite/g++.dg/gomp/block-6.C create mode 100644 gcc/testsuite/g++.dg/gomp/block-7.C create mode 100644 gcc/testsuite/g++.dg/gomp/block-8.C create mode 100644 gcc/testsuite/g++.dg/gomp/block-9.C create mode 100644 gcc/testsuite/g++.dg/gomp/clause-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/clause-2.C create mode 100644 gcc/testsuite/g++.dg/gomp/clause-3.C create mode 100644 gcc/testsuite/g++.dg/gomp/copyin-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/critical-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/critical-2.C create mode 100644 gcc/testsuite/g++.dg/gomp/flush-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/flush-2.C create mode 100644 gcc/testsuite/g++.dg/gomp/for-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/for-10.C create mode 100644 gcc/testsuite/g++.dg/gomp/for-11.C create mode 100644 gcc/testsuite/g++.dg/gomp/for-12.C create mode 100644 gcc/testsuite/g++.dg/gomp/for-13.C create mode 100644 gcc/testsuite/g++.dg/gomp/for-14.C create mode 100644 gcc/testsuite/g++.dg/gomp/for-15.C create mode 100644 gcc/testsuite/g++.dg/gomp/for-16.C create mode 100644 gcc/testsuite/g++.dg/gomp/for-17.C create mode 100644 gcc/testsuite/g++.dg/gomp/for-18.C create mode 100644 gcc/testsuite/g++.dg/gomp/for-2.C create mode 100644 gcc/testsuite/g++.dg/gomp/for-3.C create mode 100644 gcc/testsuite/g++.dg/gomp/for-4.C create mode 100644 gcc/testsuite/g++.dg/gomp/for-5.C create mode 100644 gcc/testsuite/g++.dg/gomp/for-6.C create mode 100644 gcc/testsuite/g++.dg/gomp/for-7.C create mode 100644 gcc/testsuite/g++.dg/gomp/for-8.C create mode 100644 gcc/testsuite/g++.dg/gomp/for-9.C create mode 100644 gcc/testsuite/g++.dg/gomp/gomp.exp create mode 100644 gcc/testsuite/g++.dg/gomp/macro-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/macro-2.C create mode 100644 gcc/testsuite/g++.dg/gomp/master-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/master-2.C create mode 100644 gcc/testsuite/g++.dg/gomp/master-3.C create mode 100644 gcc/testsuite/g++.dg/gomp/method-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/ordered-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/ordered-2.C create mode 100644 gcc/testsuite/g++.dg/gomp/parallel-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/parallel-2.C create mode 100644 gcc/testsuite/g++.dg/gomp/parallel-3.C create mode 100644 gcc/testsuite/g++.dg/gomp/parallel-4.C create mode 100644 gcc/testsuite/g++.dg/gomp/parallel-5.C create mode 100644 gcc/testsuite/g++.dg/gomp/pr24849.C create mode 100644 gcc/testsuite/g++.dg/gomp/pr25874.C create mode 100644 gcc/testsuite/g++.dg/gomp/sections-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/sections-2.C create mode 100644 gcc/testsuite/g++.dg/gomp/sections-3.C create mode 100644 gcc/testsuite/g++.dg/gomp/sections-4.C create mode 100644 gcc/testsuite/g++.dg/gomp/sharing-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/tls-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/tls-2.C create mode 100644 gcc/testsuite/g++.dg/gomp/tls-3.C create mode 100644 gcc/testsuite/g++.dg/gomp/tpl-atomic-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/tpl-atomic-2.C create mode 100644 gcc/testsuite/g++.dg/gomp/tpl-barrier-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/tpl-for-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/tpl-for-2.C create mode 100644 gcc/testsuite/g++.dg/gomp/tpl-for-3.C create mode 100644 gcc/testsuite/g++.dg/gomp/tpl-master-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/tpl-parallel-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/tpl-parallel-2.C create mode 100644 libgomp/testsuite/libgomp.c++/c++.exp create mode 100644 libgomp/testsuite/libgomp.c++/copyin-1.C create mode 100644 libgomp/testsuite/libgomp.c++/copyin-2.C create mode 100644 libgomp/testsuite/libgomp.c++/ctor-1.C create mode 100644 libgomp/testsuite/libgomp.c++/ctor-2.C create mode 100644 libgomp/testsuite/libgomp.c++/ctor-3.C create mode 100644 libgomp/testsuite/libgomp.c++/ctor-4.C create mode 100644 libgomp/testsuite/libgomp.c++/ctor-5.C create mode 100644 libgomp/testsuite/libgomp.c++/ctor-6.C create mode 100644 libgomp/testsuite/libgomp.c++/ctor-7.C create mode 100644 libgomp/testsuite/libgomp.c++/ctor-8.C create mode 100644 libgomp/testsuite/libgomp.c++/ctor-9.C create mode 100644 libgomp/testsuite/libgomp.c++/loop-1.C create mode 100644 libgomp/testsuite/libgomp.c++/loop-2.C create mode 100644 libgomp/testsuite/libgomp.c++/loop-3.C create mode 100644 libgomp/testsuite/libgomp.c++/loop-4.C create mode 100644 libgomp/testsuite/libgomp.c++/loop-5.C create mode 100644 libgomp/testsuite/libgomp.c++/loop-6.C create mode 100644 libgomp/testsuite/libgomp.c++/loop-7.C create mode 100644 libgomp/testsuite/libgomp.c++/master-1.C create mode 100644 libgomp/testsuite/libgomp.c++/nested-1.C create mode 100644 libgomp/testsuite/libgomp.c++/parallel-1.C create mode 100644 libgomp/testsuite/libgomp.c++/pr24455-1.C create mode 100644 libgomp/testsuite/libgomp.c++/pr24455.C create mode 100644 libgomp/testsuite/libgomp.c++/reduction-1.C create mode 100644 libgomp/testsuite/libgomp.c++/reduction-2.C create mode 100644 libgomp/testsuite/libgomp.c++/reduction-3.C create mode 100644 libgomp/testsuite/libgomp.c++/sections-1.C create mode 100644 libgomp/testsuite/libgomp.c++/shared-1.C create mode 100644 libgomp/testsuite/libgomp.c++/shared-2.C create mode 100644 libgomp/testsuite/libgomp.c++/single-1.C create mode 100644 libgomp/testsuite/libgomp.c++/single-2.C create mode 100644 libgomp/testsuite/libgomp.c++/single-3.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5a138e2529e..1f5ecd58239 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2006-03-09 Diego Novillo + + * tree-cfg.c (move_block_to_fn): Remove the statements from the + original fn's eh regions. + 2006-03-09 Eric Botcazou * fold-const.c (build_range_check): Make sure to use a valid type to diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 4c735d74c0b..60c19171303 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,452 @@ +2006-03-09 Diego Novillo + + Merge from gomp-20050608-branch + + 2006-02-02 Diego Novillo + + * decl.c (pop_labels_1): Use appropriate pointer casting. + (poplevel_named_label_1): Likewise. + (named_label_entry_hash): Likewise. + (named_label_entry_eq): Likewise. + (check_goto): Likewise. + (define_label): Likewise. + + 2006-01-26 Diego Novillo + + * cp-tree.h (CP_OMP_CLAUSE_INFO): Use TREE_TYPE instead + of TREE_BLOCK. + * pt.c: Use OMP_CLAUSE_CODE and OMP_CLAUSE_OPERAND + instead of TREE_CODE/TREE_OPERAND. + * semantics.c: Likewise. + * parser.c: Likewise. + + 2005-11-10 Diego Novillo + + * parser.c (cp_parser_omp_threadprivate): Emit diagnostic if + target does not support TLS. + + 2005-11-09 Jakub Jelinek + + * decl.c (redeclaration_error_message): Don't error about + DECL_THREAD_LOCAL_P mismatches if CP_DECL_THREADPRIVATE_P + (olddecl). + + 2005-11-08 Jakub Jelinek + + PR c++/24735 + * semantics.c (finish_omp_barrier, finish_omp_flush): New + functions. + * parser.c (cp_parser_omp_barrier): Call finish_omp_barrier. + (cp_parser_omp_flush): Call finish_omp_flush. + * cp-tree.h (finish_omp_barrier, finish_omp_flush): New + prototypes. + + PR c++/24734 + * pt.c (tsubst_expr): Handle OMP_MASTER and OMP_ORDERED. + + 2005-11-03 Jakub Jelinek + + * semantics.c (finish_omp_threadprivate): Error on class-scope + variables. + + 2005-11-02 Jakub Jelinek + + * parser.c (cp_parser_omp_all_clauses): If some clause + type is not allowed, don't remove just one of the + clauses, but all clauses added in that loop round. + + * semantics.c (finish_omp_clauses): Fix function + comment. Don't handle non-const or mutable specially, + as const and not mutable is predetermined shared and + that leads to double error. Don't ICE if copyin var is + PARM_DECL. + + PR c++/24613 + * parser.c (cp_parser_pragma): Diagnose + PRAGMA_OMP_SECTION outside of PRAGMA_OMP_SECTIONS + construct. + + * semantics.c (finish_omp_threadprivate): Error if V + is automatic variable or has incomplete type. + + 2005-11-01 Diego Novillo + + * parser.c (cp_parser_omp_all_clauses): Use + OMP_CLAUSE_CHAIN instead of TREE_CHAIN. + + 2005-11-01 Diego Novillo + + * parser.c (cp_parser_omp_all_clauses): When emitting an + error message, remove the invalid clause from the list. + + 2005-10-31 Diego Novillo + + * parser.c (cp_parser_omp_parallel): Do not allow 'nowait' in + combined parallel+workshare directives. + + 2005-10-31 Richard Henderson + + * cp-objcp-common.h (LANG_HOOKS_OMP_CLAUSE_DTOR): + Use cxx_omp_clause_dtor. + * cp-tree.h (CP_OMP_CLAUSE_INFO): New. + (cxx_omp_clause_dtor): New. + * cp-gimplify.c (cxx_omp_clause_apply_fn): New. + (cxx_omp_clause_default_ctor): Use it. + (cxx_omp_clause_copy_ctor, cxx_omp_clause_assign_op): + Likewise. + (cxx_omp_clause_dtor): New. + * semantics.c (finish_omp_clauses): Rewrite cdtor + checking to fill in CP_OMP_CLAUSE_INFO. Don't + specialcase LASTPRIVATE for removal. + (cxx_omp_clause_default_ctor, cxx_omp_clause_copy_ctor, + cxx_omp_clause_assign_op): Move to cp-gimplify.c. + + 2005-10-28 Jakub Jelinek + + * semantics.c (finish_omp_threadprivate): If + DECL_RTL_SET_P, call make_decl_rtl again so that + encode_section_info can update SYMBOL_REF's flags. + + 2005-10-26 Jakub Jelinek + + * semantics.c (finish_omp_for): Don't segfault if COND + or INCR is NULL. If not calling c_finish_omp_for + right away and one of COND and INCR is NULL, issue + error and don't expand anything. + + PR c++/24512 + * cp-tree.h (finish_omp_for): Add PRE_BODY argument. + * semantics.c (finish_omp_for): Likewise. Set + OMP_FOR_PRE_BODY to PRE_BODY if deferring, add it + into the current statement list if not processing + template decl or pass it to c_finish_omp_for. + + * parser.c (cp_parser_omp_for_loop): Expand optional DECL_EXPRs + into PRE_BODY statement list. Pass it to finish_omp_for. + * pt.c (tsubst_expr) : tsubst_expr also + OMP_FOR_PRE_BODY into PRE_BODY stmt list, pass it to + finish_omp_for. Put all the statements into sk_omp + scope. + + 2005-10-25 Jakub Jelinek + + PR c++/24516 + * parser.c (struct cp_parser): Rename in_iteration_statement + field to in_statement. + (IN_SWITCH_STMT, IN_ITERATION_STMT): Define. + (IN_OMP_BLOCK, IN_OMP_FOR): Change values. + (cp_parser_new, cp_parser_begin_omp_structured_block, + cp_parser_end_omp_structured_block, + cp_parser_omp_for_loop): Adjust for + in_iteration_statement renaming. + (cp_parser_selection_statement): Save + parser->in_iteration, or it temporarily with + IN_SWITCH_STMT for the + cp_parser_implicitly_scoped_statement call. + (cp_parser_iteration_statement): Adjust for + in_iteration_statement renaming. Use + IN_ITERATION_STMT rather than true. + (cp_parser_jump_statement): Adjust for + in_iteration_statement renaming and new values. Don't + error on break in a switch statement within OMP_FOR or + OpenMP structured block. + + PR c++/24513 + * parser.c (cp_parser_cache_group): Don't stop if next + token is CPP_PRAGMA_EOL and end is CPP_PRAGMA_EOL as + well. If current token is CPP_PRAGMA, consume + everything until CPP_PRAGMA_EOL inclusive. + + 2005-10-24 Jakub Jelinek + + PR c++/24502 + * semantics.c (finish_omp_for): Handle MODOP_EXPR in + addition to MODIFY_EXPR. + + 2005-10-23 Richard Henderson + + * cp-gimplify.c (struct cp_gimplify_ctx): Remove. + (bc_label): New. + (begin_bc_block, finish_bc_block): Use it. + (push_context, pop_context): Remove. + (cp_genericize): Don't use them. Assert bc_label is null. + * semantics.c (finish_omp_clauses): Create a fake data + element of TYPE for probing ctors. + + 2005-10-23 Richard Henderson + + * cp-objcp-common.h (LANG_HOOKS_OMP_CLAUSE_DEFAULT_CTOR): New. + (LANG_HOOKS_OMP_CLAUSE_COPY_CTOR): New. + (LANG_HOOKS_OMP_CLAUSE_ASSIGN_OP): New. + (LANG_HOOKS_OMP_CLAUSE_DTOR): New. + * semantics.c (finish_omp_clauses): Look through + arrays when looking up special member calls. Also + remove FIRSTPRIVATE when LASTPRIVATE fails. + (cxx_omp_clause_default_ctor, cxx_omp_clause_copy_ctor): New. + (cxx_omp_clause_assign_op): New. + * cp-tree.h: Declare them. + + 2005-10-21 Richard Henderson + + * decl.c (check_previous_goto_1): Return false if error. + (check_switch_goto): Likewise. + (finish_case_label): Don't emit the case label on error. + * parser.c (struct cp_parser): Revert + in_switch_statement_p changes. + (cp_parser_labeled_statement, + cp_parser_selection_statement): Likewise. + (cp_parser_begin_omp_structured_block): Don't save... + (cp_parser_end_omp_structured_block): or restore + in_switch_statement_p. + + 2005-10-21 Richard Henderson + + * semantics.c (finish_omp_threadprivate): Set + decl_flags.u2sel when necessary. + + 2005-10-21 Richard Henderson + + * decl.c (poplevel_named_label_1): Restore creation of the + bad_decls list. + (decl_jump_unsafe): Check for error_mark_node types. + (check_goto): Don't check cdtor_label. Don't use identify_goto. * semantics.c (finish_return_stmt): Do check_omp_return before + converting to cdtor_label goto. + + 2005-10-21 Richard Henderson + + PR c++/24451 + * decl.c (check_omp_return): Return false on error. + * cp-tree.h (check_omp_return): Update decl. + * semantics.c (finish_return_stmt): Avoid adding + return on error. + + 2005-10-21 Richard Henderson + + * cp-tree.h (struct language_function): Remove + x_named_label_uses. + Change x_named_labels to a hashtable. + (check_omp_return): Declare. + * decl.c (struct named_label_use_entry): Rename from + named_label_use_list. Remove label_decl. + (struct named_label_entry): Rename from + named_label_list. Remove old_value and next. Change + in_try_scope and in_catch_scope to bool. Add + in_omp_scope. + (pop_labels_1): New. + (pop_labels): Use it. + (pop_local_label, poplevel_named_label_1): New. + (poplevel): Use them. + (named_label_entry_hash, named_label_entry_eq): New. + (make_label_decl): Create named_labels. Move label + creation bits from lookup_label. + (declare_local_label): Tidy. + (identify_goto): Split out from ... + (check_previous_goto_1): Add exited_omp argument. + Handle omp scopes. + + (use_label): Merge into... + (check_goto): ... here. Handle omp scopes. + (check_omp_return): New. + (check_previous_gotos): Merge into... + (define_label): ... here. + (save_function_data): Remove x_named_label_uses reference. + (finish_function): Likewise. + * name-lookup.h (sk_omp): New. + * name-lookup.c (begin_scope): Handle it. + * parser.c (cp_parser_omp_for): Don't create extra + compound stmt. + + (cp_parser_omp_sections): Likewise. + * semantics.c (finish_return_stmt): Call check_omp_return. + (begin_omp_structured_block): Use sk_omp. + (finish_omp_structured_block): Use do_poplevel. Don't build a + MUST_NOT_THROW expression here. + (begin_omp_parallel, finish_omp_parallel): Don't create extra + compound statements. + + 2005-10-21 Diego Novillo + + PR 24455 + * cp/cp-tree.h (struct lang_decl_flags): Add field + threadprivate_p. + (CP_DECL_IS_THREADPRIVATE): Define. + * cp/semantics.c (finish_omp_threadprivate): Set. Do + not error out if CP_DECL_IS_THREADPRIVATE is set + already. + * cp/decl.c (duplicate_decls): Merge + CP_DECL_THREADPRIVATE_P. + + 2005-10-20 Richard Henderson + + * cp-gimplify.c (cp_gimplify_omp_for): New. + (cp_gimplify_expr): Call it. + * cp-tree.h (OMP_FOR_GIMPLIFYING_P): New. + * parser.c (struct cp_parser): Rename + in_iteration_statement_p to in_iteration_statement and + change to unsigned char. Similarly with + in_switch_statement. Update all users. + (IN_OMP_BLOCK, IN_OMP_FOR): New. + (cp_parser_labeled_statement): Diagnose case labels + binding closer to an openmp block nested than the + switch. + (cp_parser_jump_statement): Diagnose break and + continue labels binding closer to an openmp block than + an iteration or switch. + (cp_parser_omp_for_loop): Mark in_iteration_statement + for an omp for. + (cp_parser_begin_omp_structured_block): New. + (cp_parser_end_omp_structured_block): New. + (cp_parser_omp_structured_block): Use them. + (cp_parser_omp_for, cp_parser_omp_sections_scope): Likewise. + (cp_parser_omp_parallel): Likewise. + + 2005-10-20 Richard Henderson + + * semantics.c (begin_omp_structured_block): New. + (finish_omp_structured_block): New. + (begin_omp_parallel, finish_omp_parallel): Use them. + * parser.c (cp_parser_omp_structured_block): Likewise. + (cp_parser_omp_for): Likewise. + (cp_parser_omp_sections_scope): Likewise. + * cp-tree.h: Declare them. + + 2005-10-20 Richard Henderson + + * parser.c (cp_parser_omp_master): Return the statement. + (cp_parser_omp_ordered): Likewise. + (cp_parser_omp_construct): Set the locus for them. + + 2005-10-19 Richard Henderson + + * semantics.c (finish_omp_atomic): Revert to + uses_template_parms. + + 2005-10-19 Richard Henderson + + * semantics.c (finish_omp_clauses): Avoid + DECL_THREAD_LOCAL_P on a PARM_DECL. Remove some + stub asserts guaranteed to fail. + + 2005-10-19 Richard Henderson + + * cp-tree.h (OMP_ATOMIC_DEPENDENT_P, OMP_ATOMIC_CODE): New. + (finish_omp_clauses, finish_omp_for, finish_omp_atomic): New. + * parser.c (cp_parser_omp_clause_copyin): Remove. + (cp_parser_omp_all_clauses): Use cp_parser_omp_var_list instead. Call finish_omp_clauses. + (cp_parser_omp_clause_if): Don't do error checking here. + (cp_parser_omp_clause_num_threads): Likewise. + (cp_parser_omp_clause_schedule): Likewise. + (cp_parser_omp_atomic): Use finish_omp_atomic. + (cp_parser_omp_for_loop): Don't discard DECL_EXPR. + Don't decompose assignment statment here. Use + finish_omp_for. + + * pt.c (tsubst_omp_clauses): New. + (tsubst_expr): Handle OMP_PARALLEL, OMP_FOR, OMP_SECTIONS, + OMP_SINGLE, OMP_SECTION, OMP_CRITICAL, OMP_ATOMIC. + * semantics.c (finish_omp_clauses): New. + (begin_omp_parallel, finish_omp_parallel): Know Less about the + internals of the stmt_list stack. + (finish_omp_for, finish_omp_atomic): New. + + 2005-10-18 Jakub Jelinek + + * semantics.c (cxx_omp_predetermined_sharing): New function. + * cp-tree.h (cxx_omp_predetermined_sharing): New prototype. + * cp-objcp-common.h + (LANG_HOOKS_OMP_PREDETERMINED_SHARING): Redefine. + + 2005-10-18 Richard Henderson + + * parser.c (cp_parser_omp_single): Use make_node and accessors + instead of build. + + 2005-10-17 Richard Henderson + + * parser.c (cp_parser_omp_for_loop): Handle declarations. + + 2005-10-12 Richard Henderson + + * Make-lang.in (CXX_C_OBJS): Add c-omp.o. + * cp-tree.h (begin_omp_parallel, finish_omp_parallel): Declare. + (finish_omp_threadprivate): Declare. + * parser.c (struct cp_lexer): Add in_pragma. + (cp_lexer_consume_token): Don't consume a PRAGMA_EOL + when in_pragma. + (cp_parser_skip_to_closing_parenthesis): Stop at PRAGMA_EOL. + (cp_parser_skip_to_end_of_statement): Likewise. + (cp_parser_skip_to_end_of_block_or_statement): Likewise. + (cp_parser_skip_to_closing_brace): Likewise. + (cp_parser_skip_to_pragma_eol): Reset in_pragma. + (cp_parser_require_pragma_eol): New. + (cp_parser_statement): Add in_compound argument; + update all callers. + Restart if a non-statement pragma seen outside a + compound. + (cp_parser_statement_seq_opt): Stop at PRAGMA_EOL. + (cp_parser_declaration_seq_opt): Likewise. + (cp_parser_member_specification_opt): Likewise. + (cp_parser_function_definition_after_decl): Likewise. + (cp_parser_skip_until_found): Likewise. + (cp_parser_cache_group): Likewise. + (enum pragma_omp_clause, cp_parser_omp_clause_name, + check_no_duplicate_clause, + cp_parser_omp_var_list_no_open, + cp_parser_omp_var_list, cp_parser_omp_clause_copyin, + cp_parser_omp_clause_default, cp_parser_omp_clause_if, + cp_parser_omp_clause_nowait, + cp_parser_omp_clause_num_threads, + cp_parser_omp_clause_ordered, + cp_parser_omp_clause_reduction, + cp_parser_omp_clause_schedule, + cp_parser_omp_all_clauses, + cp_parser_omp_structured_block, cp_parser_omp_atomic, + cp_parser_omp_barrier, cp_parser_omp_critical, + cp_parser_omp_flush, cp_parser_omp_for_loop, + cp_parser_omp_for, cp_parser_omp_master, + cp_parser_omp_ordered, cp_parser_omp_sections_scope, + cp_parser_omp_sections, cp_parser_omp_parallel, + cp_parser_omp_single, cp_parser_omp_threadprivate, + cp_parser_omp_construct): New. + (cp_parser_pragma): Handle OpenMP pragmas. + * semantics.c (finish_omp_threadprivate): New. + (begin_omp_parallel, finish_omp_parallel): New. + + 2005-10-11 Richard Henderson + + * parser.c (struct cp_token): Add pragma_kind. + (eof_token): Initialize it. + (cp_lexer_handle_pragma): Remove. + (cp_parser_initial_pragma): New. + (cp_lexer_new_main): Use it. + (cp_lexer_get_preprocessor_token): Initialize pragma_kind. + (cp_lexer_print_token): Don't handle CPP_PRAGMA. + (cp_parser_skip_to_pragma_eol): New. + (cp_parser_error): Use it. + (pragma_lex): New. + + 2005-10-09 Richard Henderson + + * lex.c (parse_strconst_pragma): Update for c_lex name change. + (handle_pragma_java_exceptions): Likewise. + * parser.c (cp_lexer_new_main): Likewise. + + 2005-10-06 Richard Henderson + + * parser.c (cp_lexer_new_main): Comment out defer_pragmas. + (cp_lexer_handle_pragma): Comment out + cpp_handle_deferred_pragma. + + 2005-10-01 Richard Henderson + + * name-lookup.c (lookup_name): Remove prefer_type argument. + (lookup_name_prefer_type): New function. + * name-lookup.h (lookup_name_prefer_type): Declare it. + * decl.c (lookup_and_check_tag): Use it. + * pt.c (tsubst_friend_class): Likewise. Update for + lookup_name change. + (lookup_template_class, tsubst_copy_and_build): Likewise. + 2006-03-06 Volker Reichelt PR c++/15759 @@ -27,7 +476,7 @@ PR c++/26291 * decl.c (grok_op_properties): Check for ellipsis in arguments of - operators. + operators. 2006-02-20 Rafael Ávila de Espíndola @@ -443,10 +892,10 @@ 2006-01-20 Dirk Mueller - PR c++/5520 - * semantics.c (finish_if_stmt): Call empty_body_warning. - * parser.c (cp_parser_implicitly_scoped_statement): - Mark empty statement with an empty stmt. + PR c++/5520 + * semantics.c (finish_if_stmt): Call empty_body_warning. + * parser.c (cp_parser_implicitly_scoped_statement): + Mark empty statement with an empty stmt. 2006-01-19 Mark Mitchell @@ -572,8 +1021,8 @@ 2006-01-04 Chris Lattner - * typeck2.c: update copyright to 2006 - (split_nonconstant_init_1): Set TREE_CONSTANT to true. + * typeck2.c: update copyright to 2006 + (split_nonconstant_init_1): Set TREE_CONSTANT to true. 2006-01-04 Mark Mitchell @@ -814,7 +1263,7 @@ 2005-12-06 Aldy Hernandez PR C++/24138 - * decl.c (reshape_init_array_1): Handle max_index of -1. + * decl.c (reshape_init_array_1): Handle max_index of -1. 2005-12-06 Roger Sayle @@ -1479,7 +1928,7 @@ 2005-10-10 Giovanni Bajo Mark Mitchell - PR c++/23437 + PR c++/23437 * parser.c (cp_parser_template_argument_list): Do not treat contents of argument list as part of a constant expression. @@ -1977,27 +2426,27 @@ 2005-08-15 Fariborz Jahanian - * cp-tree.h (can_convert_arg, fn_type_unification): New argument. - * call.c (add_template_candidate_real): Pass down 'flags' to - fn_type_unification. - (can_convert_arg): New 'flags' argument. Pass it to call to - implicit_conversion instead of LOOKUP_NORMAL. + * cp-tree.h (can_convert_arg, fn_type_unification): New argument. + * call.c (add_template_candidate_real): Pass down 'flags' to + fn_type_unification. + (can_convert_arg): New 'flags' argument. Pass it to call to + implicit_conversion instead of LOOKUP_NORMAL. (can_convert): Add LOOKUP_NORMAL to call to can_convert_arg. - * class.c (resolve_address_of_overloaded_function): Ditto. - (resolve_address_of_overloaded_function): Ditto. - * decl.c (reshape_init, check_default_argument): Ditto. - * typeck.c (build_ptrmemfunc): Ditto. - * pt.c (type_unification_real): Add 'flags' argument. - (fn_type_unification): Pass 'flags' to type_unification_real. - (type_unification_real): Pass new 'flags' argument to call to - can_convert_arg. + * class.c (resolve_address_of_overloaded_function): Ditto. + (resolve_address_of_overloaded_function): Ditto. + * decl.c (reshape_init, check_default_argument): Ditto. + * typeck.c (build_ptrmemfunc): Ditto. + * pt.c (type_unification_real): Add 'flags' argument. + (fn_type_unification): Pass 'flags' to type_unification_real. + (type_unification_real): Pass new 'flags' argument to call to + can_convert_arg. 2005-08-12 Giovanni Bajo Nathan Sidwell PR c++/21799 PR c++/8271 - * pt.c (unify) : Check this-pointer cv-qualifiers + * pt.c (unify) : Check this-pointer cv-qualifiers explicitly. 2005-08-12 Nathan Sidwell @@ -2327,7 +2776,7 @@ diagnostics. 2005-07-02 Zack Weinberg - Joseph S. Myers + Joseph S. Myers * error.c (location_of): Add comment. (locate_error, cp_error_at, cp_warning_at, cp_pedwarn_at): Remove. diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index ad029f66335..63b7507fd03 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -75,7 +75,7 @@ g++-cross$(exeext): g++$(exeext) CXX_C_OBJS = attribs.o c-common.o c-format.o c-pragma.o c-semantics.o c-lex.o \ c-dump.o $(CXX_TARGET_OBJS) c-pretty-print.o c-opts.o c-pch.o \ c-incpath.o cppdefault.o c-ppoutput.o c-cppbuiltin.o prefix.o \ - c-gimplify.o tree-inline.o + c-gimplify.o c-omp.o tree-inline.o # Language-specific object files for C++ and Objective C++. CXX_AND_OBJCXX_OBJS = cp/call.o cp/decl.o cp/expr.o cp/pt.o cp/typeck2.o \ diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index a9fb7bf28e6..bd8f1a0569f 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -37,30 +37,9 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA enum bc_t { bc_break = 0, bc_continue = 1 }; -static struct cp_gimplify_ctx -{ - /* Stack of labels which are targets for "break" or "continue", - linked through TREE_CHAIN. */ - tree current_label[2]; -} *ctxp; - -static void -push_context (void) -{ - gcc_assert (!ctxp); - ctxp = ((struct cp_gimplify_ctx *) - xcalloc (1, sizeof (struct cp_gimplify_ctx))); -} - -static void -pop_context (void) -{ - gcc_assert (ctxp - && !ctxp->current_label[0] - && !ctxp->current_label[1]); - free (ctxp); - ctxp = NULL; -} +/* Stack of labels which are targets for "break" or "continue", + linked through TREE_CHAIN. */ +static tree bc_label[2]; /* Begin a scope which can be exited by a break or continue statement. BC indicates which. @@ -71,8 +50,8 @@ static tree begin_bc_block (enum bc_t bc) { tree label = create_artificial_label (); - TREE_CHAIN (label) = ctxp->current_label[bc]; - ctxp->current_label[bc] = label; + TREE_CHAIN (label) = bc_label[bc]; + bc_label[bc] = label; return label; } @@ -86,7 +65,7 @@ begin_bc_block (enum bc_t bc) static tree finish_bc_block (enum bc_t bc, tree label, tree body) { - gcc_assert (label == ctxp->current_label[bc]); + gcc_assert (label == bc_label[bc]); if (TREE_USED (label)) { @@ -99,7 +78,7 @@ finish_bc_block (enum bc_t bc, tree label, tree body) body = sl; } - ctxp->current_label[bc] = TREE_CHAIN (label); + bc_label[bc] = TREE_CHAIN (label); TREE_CHAIN (label) = NULL_TREE; return body; } @@ -110,7 +89,7 @@ finish_bc_block (enum bc_t bc, tree label, tree body) static tree build_bc_goto (enum bc_t bc) { - tree label = ctxp->current_label[bc]; + tree label = bc_label[bc]; if (label == NULL_TREE) { @@ -338,6 +317,36 @@ gimplify_switch_stmt (tree *stmt_p) *stmt_p = finish_bc_block (bc_break, break_block, *stmt_p); } +/* Hook into the middle of gimplifying an OMP_FOR node. This is required + in order to properly gimplify CONTINUE statements. Here we merely + manage the continue stack; the rest of the job is performed by the + regular gimplifier. */ + +static enum gimplify_status +cp_gimplify_omp_for (tree *expr_p) +{ + tree for_stmt = *expr_p; + tree cont_block; + + /* Protect ourselves from recursion. */ + if (OMP_FOR_GIMPLIFYING_P (for_stmt)) + return GS_UNHANDLED; + OMP_FOR_GIMPLIFYING_P (for_stmt) = 1; + + /* Note that while technically the continue label is enabled too soon + here, we should have already diagnosed invalid continues nested within + statement expressions within the INIT, COND, or INCR expressions. */ + cont_block = begin_bc_block (bc_continue); + + gimplify_stmt (expr_p); + + OMP_FOR_BODY (for_stmt) + = finish_bc_block (bc_continue, cont_block, OMP_FOR_BODY (for_stmt)); + OMP_FOR_GIMPLIFYING_P (for_stmt) = 0; + + return GS_ALL_DONE; +} + /* Gimplify an EXPR_STMT node. */ static void @@ -543,6 +552,10 @@ cp_gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p) ret = GS_ALL_DONE; break; + case OMP_FOR: + ret = cp_gimplify_omp_for (expr_p); + break; + case CONTINUE_STMT: *expr_p = build_bc_goto (bc_continue); ret = GS_ALL_DONE; @@ -686,7 +699,157 @@ cp_genericize (tree fndecl) pointer_set_destroy (p_set); /* Do everything else. */ - push_context (); c_genericize (fndecl); - pop_context (); + + gcc_assert (bc_label[bc_break] == NULL); + gcc_assert (bc_label[bc_continue] == NULL); +} + +/* Build code to apply FN to each member of ARG1 and ARG2. FN may be + NULL if there is in fact nothing to do. ARG2 may be null if FN + actually only takes one argument. */ + +static tree +cxx_omp_clause_apply_fn (tree fn, tree arg1, tree arg2) +{ + if (fn == NULL) + return NULL; + + if (TREE_CODE (TREE_TYPE (arg1)) == ARRAY_TYPE) + { + tree inner_type = TREE_TYPE (arg1); + tree start1, end1, p1; + tree start2 = NULL, p2 = NULL; + tree ret = NULL, lab, t; + + start1 = arg1; + start2 = arg2; + do + { + inner_type = TREE_TYPE (inner_type); + start1 = build4 (ARRAY_REF, inner_type, start1, + size_zero_node, NULL, NULL); + if (arg2) + start2 = build4 (ARRAY_REF, inner_type, start2, + size_zero_node, NULL, NULL); + } + while (TREE_CODE (inner_type) == ARRAY_TYPE); + start1 = build_fold_addr_expr (start1); + if (arg2) + start2 = build_fold_addr_expr (start2); + + end1 = TYPE_SIZE_UNIT (TREE_TYPE (arg1)); + end1 = fold_convert (TREE_TYPE (start1), end1); + end1 = build2 (PLUS_EXPR, TREE_TYPE (start1), start1, end1); + + p1 = create_tmp_var (TREE_TYPE (start1), NULL); + t = build2 (MODIFY_EXPR, void_type_node, p1, start1); + append_to_statement_list (t, &ret); + + if (arg2) + { + p2 = create_tmp_var (TREE_TYPE (start2), NULL); + t = build2 (MODIFY_EXPR, void_type_node, p2, start2); + append_to_statement_list (t, &ret); + } + + lab = create_artificial_label (); + t = build1 (LABEL_EXPR, void_type_node, lab); + append_to_statement_list (t, &ret); + + t = NULL; + if (arg2) + t = tree_cons (NULL, p2, t); + t = tree_cons (NULL, p1, t); + t = build_call (fn, t); + append_to_statement_list (t, &ret); + + t = fold_convert (TREE_TYPE (p1), TYPE_SIZE_UNIT (inner_type)); + t = build2 (PLUS_EXPR, TREE_TYPE (p1), p1, t); + t = build2 (MODIFY_EXPR, void_type_node, p1, t); + append_to_statement_list (t, &ret); + + if (arg2) + { + t = fold_convert (TREE_TYPE (p2), TYPE_SIZE_UNIT (inner_type)); + t = build2 (PLUS_EXPR, TREE_TYPE (p2), p2, t); + t = build2 (MODIFY_EXPR, void_type_node, p2, t); + append_to_statement_list (t, &ret); + } + + t = build2 (NE_EXPR, boolean_type_node, p1, end1); + t = build3 (COND_EXPR, void_type_node, t, build_and_jump (&lab), NULL); + append_to_statement_list (t, &ret); + + return ret; + } + else + { + tree t = NULL; + if (arg2) + t = tree_cons (NULL, build_fold_addr_expr (arg2), t); + t = tree_cons (NULL, build_fold_addr_expr (arg1), t); + return build_call (fn, t); + } +} + +/* Return code to initialize DECL with its default constructor, or + NULL if there's nothing to do. */ + +tree +cxx_omp_clause_default_ctor (tree clause, tree decl) +{ + tree info = CP_OMP_CLAUSE_INFO (clause); + tree ret = NULL; + + if (info) + ret = cxx_omp_clause_apply_fn (TREE_VEC_ELT (info, 0), decl, NULL); + + return ret; +} + +/* Return code to initialize DST with a copy constructor from SRC. */ + +tree +cxx_omp_clause_copy_ctor (tree clause, tree dst, tree src) +{ + tree info = CP_OMP_CLAUSE_INFO (clause); + tree ret = NULL; + + if (info) + ret = cxx_omp_clause_apply_fn (TREE_VEC_ELT (info, 0), dst, src); + if (ret == NULL) + ret = build2 (MODIFY_EXPR, void_type_node, dst, src); + + return ret; +} + +/* Similarly, except use an assignment operator instead. */ + +tree +cxx_omp_clause_assign_op (tree clause, tree dst, tree src) +{ + tree info = CP_OMP_CLAUSE_INFO (clause); + tree ret = NULL; + + if (info) + ret = cxx_omp_clause_apply_fn (TREE_VEC_ELT (info, 2), dst, src); + if (ret == NULL) + ret = build2 (MODIFY_EXPR, void_type_node, dst, src); + + return ret; +} + +/* Return code to destroy DECL. */ + +tree +cxx_omp_clause_dtor (tree clause, tree decl) +{ + tree info = CP_OMP_CLAUSE_INFO (clause); + tree ret = NULL; + + if (info) + ret = cxx_omp_clause_apply_fn (TREE_VEC_ELT (info, 1), decl, NULL); + + return ret; } diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h index 4a4d400cd6f..96e6eb699dc 100644 --- a/gcc/cp/cp-objcp-common.h +++ b/gcc/cp/cp-objcp-common.h @@ -151,5 +151,15 @@ extern tree objcp_tsubst_copy_and_build (tree, tree, tsubst_flags_t, #define LANG_HOOKS_TO_TARGET_CHARSET c_common_to_target_charset #undef LANG_HOOKS_GIMPLIFY_EXPR #define LANG_HOOKS_GIMPLIFY_EXPR cp_gimplify_expr +#undef LANG_HOOKS_OMP_PREDETERMINED_SHARING +#define LANG_HOOKS_OMP_PREDETERMINED_SHARING cxx_omp_predetermined_sharing +#undef LANG_HOOKS_OMP_CLAUSE_DEFAULT_CTOR +#define LANG_HOOKS_OMP_CLAUSE_DEFAULT_CTOR cxx_omp_clause_default_ctor +#undef LANG_HOOKS_OMP_CLAUSE_COPY_CTOR +#define LANG_HOOKS_OMP_CLAUSE_COPY_CTOR cxx_omp_clause_copy_ctor +#undef LANG_HOOKS_OMP_CLAUSE_ASSIGN_OP +#define LANG_HOOKS_OMP_CLAUSE_ASSIGN_OP cxx_omp_clause_assign_op +#undef LANG_HOOKS_OMP_CLAUSE_DTOR +#define LANG_HOOKS_OMP_CLAUSE_DTOR cxx_omp_clause_dtor #endif /* GCC_CP_OBJCP_COMMON */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 2f67f374ff3..69d64667502 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -52,6 +52,8 @@ struct diagnostic_context; TYPENAME_IS_ENUM_P (in TYPENAME_TYPE) REFERENCE_REF_P (in INDIRECT_EXPR) QUALIFIED_NAME_IS_TEMPLATE (in SCOPE_REF) + OMP_ATOMIC_DEPENDENT_P (in OMP_ATOMIC) + OMP_FOR_GIMPLIFYING_P (in OMP_FOR) BASELINK_QUALIFIED_P (in BASELINK) 1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE) TI_PENDING_TEMPLATE_FLAG. @@ -742,8 +744,7 @@ struct language_function GTY(()) /* True if this function can throw an exception. */ BOOL_BITFIELD can_throw : 1; - struct named_label_use_list *x_named_label_uses; - struct named_label_list *x_named_labels; + htab_t GTY((param_is(struct named_label_entry))) x_named_labels; struct cp_binding_level *bindings; VEC(tree,gc) *x_local_names; }; @@ -1521,7 +1522,8 @@ struct lang_decl_flags GTY(()) unsigned this_thunk_p : 1; unsigned repo_available_p : 1; unsigned hidden_friend_p : 1; - unsigned dummy : 2; + unsigned threadprivate_p : 1; + /* One unused bit. */ union lang_decl_u { /* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is @@ -2348,6 +2350,11 @@ extern void decl_shadowed_for_var_insert (tree, tree); #define DECL_HIDDEN_FRIEND_P(NODE) \ (DECL_LANG_SPECIFIC (DECL_COMMON_CHECK (NODE))->decl_flags.hidden_friend_p) +/* Nonzero if DECL has been declared threadprivate by + #pragma omp threadprivate. */ +#define CP_DECL_THREADPRIVATE_P(DECL) \ + (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (DECL))->decl_flags.threadprivate_p) + /* Record whether a typedef for type `int' was actually `signed int'. */ #define C_TYPEDEF_EXPLICITLY_SIGNED(EXP) DECL_LANG_FLAG_1 (EXP) @@ -2947,6 +2954,26 @@ extern void decl_shadowed_for_var_insert (tree, tree); #define QUALIFIED_NAME_IS_TEMPLATE(NODE) \ (TREE_LANG_FLAG_0 (SCOPE_REF_CHECK (NODE))) +/* True for an OMP_ATOMIC that has dependent parameters. These are stored + as bare LHS/RHS, and not as ADDR/RHS, as in the generic statement. */ +#define OMP_ATOMIC_DEPENDENT_P(NODE) \ + (TREE_LANG_FLAG_0 (OMP_ATOMIC_CHECK (NODE))) + +/* Used to store the operation code when OMP_ATOMIC_DEPENDENT_P is set. */ +#define OMP_ATOMIC_CODE(NODE) \ + (OMP_ATOMIC_CHECK (NODE)->exp.complexity) + +/* Used while gimplifying continue statements bound to OMP_FOR nodes. */ +#define OMP_FOR_GIMPLIFYING_P(NODE) \ + (TREE_LANG_FLAG_0 (OMP_FOR_CHECK (NODE))) + +/* A language-specific token attached to the OpenMP data clauses to + hold code (or code fragments) related to ctors, dtors, and op=. + See semantics.c for details. */ +#define CP_OMP_CLAUSE_INFO(NODE) \ + TREE_TYPE (OMP_CLAUSE_RANGE_CHECK (NODE, OMP_CLAUSE_PRIVATE, \ + OMP_CLAUSE_COPYPRIVATE)) + /* These macros provide convenient access to the various _STMT nodes created when parsing template declarations. */ #define TRY_STMTS(NODE) TREE_OPERAND (TRY_BLOCK_CHECK (NODE), 0) @@ -3782,12 +3809,12 @@ extern tree pushtag (tree, tree, tag_scope); extern tree make_anon_name (void); extern int decls_match (tree, tree); extern tree duplicate_decls (tree, tree, bool); -extern tree pushdecl_top_level (tree); extern tree pushdecl_top_level_maybe_friend (tree, bool); extern tree pushdecl_top_level_and_finish (tree, tree); extern tree declare_local_label (tree); extern tree define_label (location_t, tree); extern void check_goto (tree); +extern bool check_omp_return (void); extern tree make_typename_type (tree, tree, enum tag_types, tsubst_flags_t); extern tree make_unbound_class_template (tree, tree, tree, tsubst_flags_t); extern tree check_for_out_of_scope_variable (tree); @@ -4216,6 +4243,22 @@ extern tree finish_qualified_id_expr (tree, tree, bool, bool, extern void simplify_aggr_init_expr (tree *); extern void finalize_nrv (tree *, tree, tree); extern void note_decl_for_pch (tree); +extern tree finish_omp_clauses (tree); +extern void finish_omp_threadprivate (tree); +extern tree begin_omp_structured_block (void); +extern tree finish_omp_structured_block (tree); +extern tree begin_omp_parallel (void); +extern tree finish_omp_parallel (tree, tree); +extern tree finish_omp_for (location_t, tree, tree, + tree, tree, tree, tree); +extern void finish_omp_atomic (enum tree_code, tree, tree); +extern void finish_omp_barrier (void); +extern void finish_omp_flush (void); +extern enum omp_clause_default_kind cxx_omp_predetermined_sharing (tree); +extern tree cxx_omp_clause_default_ctor (tree, tree); +extern tree cxx_omp_clause_copy_ctor (tree, tree, tree); +extern tree cxx_omp_clause_assign_op (tree, tree, tree); +extern tree cxx_omp_clause_dtor (tree, tree); /* in tree.c */ extern void lang_check_failed (const char *, int, diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index a9aec670634..d0866dc5b3d 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -80,15 +80,6 @@ static tree record_builtin_java_type (const char *, int); static const char *tag_name (enum tag_types); static tree lookup_and_check_tag (enum tag_types, tree, tag_scope, bool); static int walk_namespaces_r (tree, walk_namespaces_fn, void *); -static tree make_label_decl (tree, int); -static void use_label (tree); -static void check_previous_goto_1 (tree, struct cp_binding_level *, tree, - const location_t *); -static void check_previous_goto (struct named_label_use_list *); -static void check_switch_goto (struct cp_binding_level *); -static void check_previous_gotos (tree); -static void pop_label (tree, tree); -static void pop_labels (tree); static void maybe_deduce_size_from_array_init (tree, tree); static void layout_var_decl (tree); static void maybe_commonize_var (tree); @@ -167,20 +158,6 @@ tree global_type_node; /* The node that holds the "name" of the global scope. */ tree global_scope_name; -/* Used only for jumps to as-yet undefined labels, since jumps to - defined labels can have their validity checked immediately. */ - -struct named_label_use_list GTY(()) -{ - struct cp_binding_level *binding_level; - tree names_in_scope; - tree label_decl; - location_t o_goto_locus; - struct named_label_use_list *next; -}; - -#define named_label_uses cp_function_chain->x_named_label_uses - #define local_names cp_function_chain->x_local_names /* A list of objects which have constructors or destructors @@ -195,20 +172,58 @@ tree static_aggregates; tree integer_two_node, integer_three_node; +/* Used only for jumps to as-yet undefined labels, since jumps to + defined labels can have their validity checked immediately. */ + +struct named_label_use_entry GTY(()) +{ + struct named_label_use_entry *next; + /* The binding level to which this entry is *currently* attached. + This is initially the binding level in which the goto appeared, + but is modified as scopes are closed. */ + struct cp_binding_level *binding_level; + /* The head of the names list that was current when the goto appeared, + or the inner scope popped. These are the decls that will *not* be + skipped when jumping to the label. */ + tree names_in_scope; + /* The location of the goto, for error reporting. */ + location_t o_goto_locus; + /* True if an OpenMP structured block scope has been closed since + the goto appeared. This means that the branch from the label will + illegally exit an OpenMP scope. */ + bool in_omp_scope; +}; + /* A list of all LABEL_DECLs in the function that have names. Here so we can clear out their names' definitions at the end of the function, and so we can check the validity of jumps to these labels. */ -struct named_label_list GTY(()) +struct named_label_entry GTY(()) { + /* The decl itself. */ + tree label_decl; + + /* The binding level to which the label is *currently* attached. + This is initially set to the binding level in which the label + is defined, but is modified as scopes are closed. */ struct cp_binding_level *binding_level; + /* The head of the names list that was current when the label was + defined, or the inner scope popped. These are the decls that will + be skipped when jumping to the label. */ tree names_in_scope; - tree old_value; - tree label_decl; + /* A tree list of all decls from all binding levels that would be + crossed by a backward branch to the label. */ tree bad_decls; - struct named_label_list *next; - unsigned int in_try_scope : 1; - unsigned int in_catch_scope : 1; + + /* A list of uses of the label, before the label is defined. */ + struct named_label_use_entry *uses; + + /* The following bits are set after the label is defined, and are + updated as scopes are popped. They indicate that a backward jump + to the label will illegally enter a scope of the given flavour. */ + bool in_try_scope; + bool in_catch_scope; + bool in_omp_scope; }; #define named_labels cp_function_chain->x_named_labels @@ -372,23 +387,47 @@ pop_label (tree label, tree old_value) go out of scope. BLOCK is the top-level block for the function. */ +static int +pop_labels_1 (void **slot, void *data) +{ + struct named_label_entry *ent = (struct named_label_entry *) *slot; + tree block = (tree) data; + + pop_label (ent->label_decl, NULL_TREE); + + /* Put the labels into the "variables" of the top-level block, + so debugger can see them. */ + TREE_CHAIN (ent->label_decl) = BLOCK_VARS (block); + BLOCK_VARS (block) = ent->label_decl; + + htab_clear_slot (named_labels, slot); + + return 1; +} + static void pop_labels (tree block) { - struct named_label_list *link; - - /* Clear out the definitions of all label names, since their scopes - end here. */ - for (link = named_labels; link; link = link->next) + if (named_labels) { - pop_label (link->label_decl, link->old_value); - /* Put the labels into the "variables" of the top-level block, - so debugger can see them. */ - TREE_CHAIN (link->label_decl) = BLOCK_VARS (block); - BLOCK_VARS (block) = link->label_decl; + htab_traverse (named_labels, pop_labels_1, block); + named_labels = NULL; } +} + +/* At the end of a block with local labels, restore the outer definition. */ - named_labels = NULL; +static void +pop_local_label (tree label, tree old_value) +{ + struct named_label_entry dummy; + void **slot; + + pop_label (label, old_value); + + dummy.label_decl = label; + slot = htab_find_slot (named_labels, &dummy, NO_INSERT); + htab_clear_slot (named_labels, slot); } /* The following two routines are used to interface to Objective-C++. @@ -426,6 +465,57 @@ objc_mark_locals_volatile (void *enclosing_blk) } } +/* Update data for defined and undefined labels when leaving a scope. */ + +static int +poplevel_named_label_1 (void **slot, void *data) +{ + struct named_label_entry *ent = (struct named_label_entry *) *slot; + struct cp_binding_level *bl = (struct cp_binding_level *) data; + struct cp_binding_level *obl = bl->level_chain; + + if (ent->binding_level == bl) + { + tree decl; + + for (decl = ent->names_in_scope; decl; decl = TREE_CHAIN (decl)) + if (decl_jump_unsafe (decl)) + ent->bad_decls = tree_cons (NULL, decl, ent->bad_decls); + + ent->binding_level = obl; + ent->names_in_scope = obl->names; + switch (bl->kind) + { + case sk_try: + ent->in_try_scope = true; + break; + case sk_catch: + ent->in_catch_scope = true; + break; + case sk_omp: + ent->in_omp_scope = true; + break; + default: + break; + } + } + else if (ent->uses) + { + struct named_label_use_entry *use; + + for (use = ent->uses; use ; use = use->next) + if (use->binding_level == bl) + { + use->binding_level = obl; + use->names_in_scope = obl->names; + if (bl->kind == sk_omp) + use->in_omp_scope = true; + } + } + + return 1; +} + /* Exit a binding level. Pop the level off, and restore the state of the identifier-decl mappings that were in effect when this level was entered. @@ -480,39 +570,9 @@ poplevel (int keep, int reverse, int functionbody) /* Any uses of undefined labels, and any defined labels, now operate under constraints of next binding contour. */ - if (cfun && !functionbody) - { - struct cp_binding_level *level_chain; - level_chain = current_binding_level->level_chain; - if (level_chain) - { - struct named_label_use_list *uses; - struct named_label_list *labels; - for (labels = named_labels; labels; labels = labels->next) - if (labels->binding_level == current_binding_level) - { - tree decl; - if (current_binding_level->kind == sk_try) - labels->in_try_scope = 1; - if (current_binding_level->kind == sk_catch) - labels->in_catch_scope = 1; - for (decl = labels->names_in_scope; decl; - decl = TREE_CHAIN (decl)) - if (decl_jump_unsafe (decl)) - labels->bad_decls = tree_cons (NULL_TREE, decl, - labels->bad_decls); - labels->binding_level = level_chain; - labels->names_in_scope = level_chain->names; - } - - for (uses = named_label_uses; uses; uses = uses->next) - if (uses->binding_level == current_binding_level) - { - uses->binding_level = level_chain; - uses->names_in_scope = level_chain->names; - } - } - } + if (cfun && !functionbody && named_labels) + htab_traverse (named_labels, poplevel_named_label_1, + current_binding_level); /* Get the decls in the order they were written. Usually current_binding_level->names is in reverse order. @@ -660,7 +720,7 @@ poplevel (int keep, int reverse, int functionbody) for (link = current_binding_level->shadowed_labels; link; link = TREE_CHAIN (link)) - pop_label (TREE_VALUE (link), TREE_PURPOSE (link)); + pop_local_label (TREE_VALUE (link), TREE_PURPOSE (link)); /* There may be OVERLOADs (wrapped in TREE_LISTs) on the BLOCK_VARs list if a `using' declaration put them there. The debugging @@ -1585,6 +1645,18 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) |= DECL_NONTRIVIALLY_INITIALIZED_P (olddecl); DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (newdecl) |= DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (olddecl); + + /* Merge the threadprivate attribute from OLDDECL into NEWDECL. */ + if (DECL_LANG_SPECIFIC (olddecl) + && CP_DECL_THREADPRIVATE_P (olddecl)) + { + /* Allocate a LANG_SPECIFIC structure for NEWDECL, if needed. */ + if (!DECL_LANG_SPECIFIC (newdecl)) + retrofit_lang_decl (newdecl); + + DECL_TLS_MODEL (newdecl) = DECL_TLS_MODEL (olddecl); + CP_DECL_THREADPRIVATE_P (newdecl) = 1; + } } /* Do this after calling `merge_types' so that default @@ -2039,7 +2111,10 @@ redeclaration_error_message (tree newdecl, tree olddecl) return NULL; } else if (TREE_CODE (newdecl) == VAR_DECL - && DECL_THREAD_LOCAL_P (newdecl) != DECL_THREAD_LOCAL_P (olddecl)) + && DECL_THREAD_LOCAL_P (newdecl) != DECL_THREAD_LOCAL_P (olddecl) + && (! DECL_LANG_SPECIFIC (olddecl) + || ! CP_DECL_THREADPRIVATE_P (olddecl) + || DECL_THREAD_LOCAL_P (newdecl))) { /* Only variables can be thread-local, and all declarations must agree on this property. */ @@ -2070,11 +2145,30 @@ redeclaration_error_message (tree newdecl, tree olddecl) } } +/* Hash and equality functions for the named_label table. */ + +static hashval_t +named_label_entry_hash (const void *data) +{ + const struct named_label_entry *ent = (const struct named_label_entry *) data; + return DECL_UID (ent->label_decl); +} + +static int +named_label_entry_eq (const void *a, const void *b) +{ + const struct named_label_entry *ent_a = (const struct named_label_entry *) a; + const struct named_label_entry *ent_b = (const struct named_label_entry *) b; + return ent_a->label_decl == ent_b->label_decl; +} + /* Create a new label, named ID. */ static tree make_label_decl (tree id, int local_p) { + struct named_label_entry *ent; + void **slot; tree decl; decl = build_decl (LABEL_DECL, id, void_type_node); @@ -2090,30 +2184,22 @@ make_label_decl (tree id, int local_p) /* Record the fact that this identifier is bound to this label. */ SET_IDENTIFIER_LABEL_VALUE (id, decl); - return decl; -} + /* Create the label htab for the function on demand. */ + if (!named_labels) + named_labels = htab_create_ggc (13, named_label_entry_hash, + named_label_entry_eq, NULL); -/* Record this label on the list of used labels so that we can check - at the end of the function to see whether or not the label was - actually defined, and so we can check when the label is defined whether - this use is valid. */ + /* Record this label on the list of labels used in this function. + We do this before calling make_label_decl so that we get the + IDENTIFIER_LABEL_VALUE before the new label is declared. */ + ent = GGC_CNEW (struct named_label_entry); + ent->label_decl = decl; -static void -use_label (tree decl) -{ - if (named_label_uses == NULL - || named_label_uses->names_in_scope != current_binding_level->names - || named_label_uses->label_decl != decl) - { - struct named_label_use_list *new_ent; - new_ent = GGC_NEW (struct named_label_use_list); - new_ent->label_decl = decl; - new_ent->names_in_scope = current_binding_level->names; - new_ent->binding_level = current_binding_level; - new_ent->o_goto_locus = input_location; - new_ent->next = named_label_uses; - named_label_uses = new_ent; - } + slot = htab_find_slot (named_labels, ent, INSERT); + gcc_assert (*slot == NULL); + *slot = ent; + + return decl; } /* Look for a label named ID in the current function. If one cannot @@ -2124,7 +2210,6 @@ tree lookup_label (tree id) { tree decl; - struct named_label_list *ent; timevar_push (TV_NAME_LOOKUP); /* You can't use labels at global scope. */ @@ -2139,20 +2224,7 @@ lookup_label (tree id) if (decl != NULL_TREE && DECL_CONTEXT (decl) == current_function_decl) POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, decl); - /* Record this label on the list of labels used in this function. - We do this before calling make_label_decl so that we get the - IDENTIFIER_LABEL_VALUE before the new label is declared. */ - ent = GGC_CNEW (struct named_label_list); - ent->old_value = IDENTIFIER_LABEL_VALUE (id); - ent->next = named_labels; - named_labels = ent; - - /* We need a new label. */ decl = make_label_decl (id, /*local_p=*/0); - - /* Now fill in the information we didn't have before. */ - ent->label_decl = decl; - POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, decl); } @@ -2161,18 +2233,16 @@ lookup_label (tree id) tree declare_local_label (tree id) { - tree decl; + tree decl, shadow; /* Add a new entry to the SHADOWED_LABELS list so that when we leave - this scope we can restore the old value of - IDENTIFIER_TYPE_VALUE. */ - current_binding_level->shadowed_labels - = tree_cons (IDENTIFIER_LABEL_VALUE (id), NULL_TREE, - current_binding_level->shadowed_labels); - /* Look for the label. */ + this scope we can restore the old value of IDENTIFIER_TYPE_VALUE. */ + shadow = tree_cons (IDENTIFIER_LABEL_VALUE (id), NULL_TREE, + current_binding_level->shadowed_labels); + current_binding_level->shadowed_labels = shadow; + decl = make_label_decl (id, /*local_p=*/1); - /* Now fill in the information we didn't have before. */ - TREE_VALUE (current_binding_level->shadowed_labels) = decl; + TREE_VALUE (shadow) = decl; return decl; } @@ -2199,42 +2269,55 @@ decl_jump_unsafe (tree decl) return 1; } +/* A subroutine of check_previous_goto_1 to identify a branch to the user. */ + +static void +identify_goto (tree decl, const location_t *locus) +{ + if (decl) + pedwarn ("jump to label %qD", decl); + else + pedwarn ("jump to case label"); + if (locus) + pedwarn ("%H from here", locus); +} + /* Check that a single previously seen jump to a newly defined label is OK. DECL is the LABEL_DECL or 0; LEVEL is the binding_level for the jump context; NAMES are the names in scope in LEVEL at the jump - context; FILE and LINE are the source position of the jump or 0. */ + context; LOCUS is the source position of the jump or 0. Returns + true if all is well. */ -static void -check_previous_goto_1 (tree decl, - struct cp_binding_level* level, - tree names, const location_t *locus) -{ - int identified = 0; - int saw_eh = 0; - struct cp_binding_level *b = current_binding_level; - for (; b; b = b->level_chain) - { - tree new_decls = b->names; - tree old_decls = (b == level ? names : NULL_TREE); - for (; new_decls != old_decls; +static bool +check_previous_goto_1 (tree decl, struct cp_binding_level* level, tree names, + bool exited_omp, const location_t *locus) +{ + struct cp_binding_level *b; + bool identified = false, saw_eh = false, saw_omp = false; + + if (exited_omp) + { + identify_goto (decl, locus); + error (" exits OpenMP structured block"); + identified = saw_omp = true; + } + + for (b = current_binding_level; b ; b = b->level_chain) + { + tree new_decls, old_decls = (b == level ? names : NULL_TREE); + + for (new_decls = b->names; new_decls != old_decls; new_decls = TREE_CHAIN (new_decls)) { int problem = decl_jump_unsafe (new_decls); if (! problem) continue; - if (! identified) + if (!identified) { - if (decl) - pedwarn ("jump to label %qD", decl); - else - pedwarn ("jump to case label"); - - if (locus) - pedwarn ("%H from here", locus); - identified = 1; + identify_goto (decl, locus); + identified = true; } - if (problem > 1) error (" crosses initialization of %q+#D", new_decls); else @@ -2243,63 +2326,46 @@ check_previous_goto_1 (tree decl, if (b == level) break; - if ((b->kind == sk_try || b->kind == sk_catch) && ! saw_eh) + if ((b->kind == sk_try || b->kind == sk_catch) && !saw_eh) { - if (! identified) + if (!identified) { - if (decl) - pedwarn ("jump to label %qD", decl); - else - pedwarn ("jump to case label"); - - if (locus) - pedwarn ("%H from here", locus); - identified = 1; + identify_goto (decl, locus); + identified = true; } if (b->kind == sk_try) error (" enters try block"); else error (" enters catch block"); - saw_eh = 1; + saw_eh = true; + } + if (b->kind == sk_omp && !saw_omp) + { + if (!identified) + { + identify_goto (decl, locus); + identified = true; + } + error (" enters OpenMP structured block"); + saw_omp = true; } } + + return !identified; } static void -check_previous_goto (struct named_label_use_list* use) +check_previous_goto (tree decl, struct named_label_use_entry *use) { - check_previous_goto_1 (use->label_decl, use->binding_level, - use->names_in_scope, &use->o_goto_locus); + check_previous_goto_1 (decl, use->binding_level, + use->names_in_scope, use->in_omp_scope, + &use->o_goto_locus); } -static void +static bool check_switch_goto (struct cp_binding_level* level) { - check_previous_goto_1 (NULL_TREE, level, level->names, NULL); -} - -/* Check that any previously seen jumps to a newly defined label DECL - are OK. Called by define_label. */ - -static void -check_previous_gotos (tree decl) -{ - struct named_label_use_list **usep; - - if (! TREE_USED (decl)) - return; - - for (usep = &named_label_uses; *usep; ) - { - struct named_label_use_list *use = *usep; - if (use->label_decl == decl) - { - check_previous_goto (use); - *usep = use->next; - } - else - usep = &(use->next); - } + return check_previous_goto_1 (NULL_TREE, level, level->names, false, NULL); } /* Check that a new jump to a label DECL is OK. Called by @@ -2308,57 +2374,114 @@ check_previous_gotos (tree decl) void check_goto (tree decl) { - int identified = 0; + struct named_label_entry *ent, dummy; + bool saw_catch = false, identified = false; tree bad; - struct named_label_list *lab; - /* We can't know where a computed goto is jumping. So we assume - that it's OK. */ - if (! DECL_P (decl)) + /* We can't know where a computed goto is jumping. + So we assume that it's OK. */ + if (TREE_CODE (decl) != LABEL_DECL) + return; + + /* We didn't record any information about this label when we created it, + and there's not much point since it's trivial to analyze as a return. */ + if (decl == cdtor_label) return; + dummy.label_decl = decl; + ent = (struct named_label_entry *) htab_find (named_labels, &dummy); + gcc_assert (ent != NULL); + /* If the label hasn't been defined yet, defer checking. */ if (! DECL_INITIAL (decl)) { - use_label (decl); - return; - } + struct named_label_use_entry *new_use; - for (lab = named_labels; lab; lab = lab->next) - if (decl == lab->label_decl) - break; + /* Don't bother creating another use if the last goto had the + same data, and will therefore create the same set of errors. */ + if (ent->uses + && ent->uses->names_in_scope == current_binding_level->names) + return; - /* If the label is not on named_labels it's a gcc local label, so - it must be in an outer scope, so jumping to it is always OK. */ - if (lab == 0) - return; + new_use = GGC_NEW (struct named_label_use_entry); + new_use->binding_level = current_binding_level; + new_use->names_in_scope = current_binding_level->names; + new_use->o_goto_locus = input_location; + new_use->in_omp_scope = false; - if ((lab->in_try_scope || lab->in_catch_scope || lab->bad_decls) - && !identified) + new_use->next = ent->uses; + ent->uses = new_use; + return; + } + + if (ent->in_try_scope || ent->in_catch_scope + || ent->in_omp_scope || ent->bad_decls) { pedwarn ("jump to label %q+D", decl); pedwarn (" from here"); - identified = 1; + identified = true; } - for (bad = lab->bad_decls; bad; bad = TREE_CHAIN (bad)) + for (bad = ent->bad_decls; bad; bad = TREE_CHAIN (bad)) { tree b = TREE_VALUE (bad); int u = decl_jump_unsafe (b); if (u > 1 && DECL_ARTIFICIAL (b)) - /* Can't skip init of __exception_info. */ - error ("%J enters catch block", b); + { + /* Can't skip init of __exception_info. */ + error ("%J enters catch block", b); + saw_catch = true; + } else if (u > 1) error (" skips initialization of %q+#D", b); else pedwarn (" enters scope of non-POD %q+#D", b); } - if (lab->in_try_scope) + if (ent->in_try_scope) error (" enters try block"); - else if (lab->in_catch_scope) + else if (ent->in_catch_scope && !saw_catch) error (" enters catch block"); + + if (ent->in_omp_scope) + error (" enters OpenMP structured block"); + else if (flag_openmp) + { + struct cp_binding_level *b; + for (b = current_binding_level; b ; b = b->level_chain) + { + if (b == ent->binding_level) + break; + if (b->kind == sk_omp) + { + if (!identified) + { + pedwarn ("jump to label %q+D", decl); + pedwarn (" from here"); + identified = true; + } + error (" exits OpenMP structured block"); + break; + } + } + } +} + +/* Check that a return is ok wrt OpenMP structured blocks. + Called by finish_return_stmt. Returns true if all is well. */ + +bool +check_omp_return (void) +{ + struct cp_binding_level *b; + for (b = current_binding_level; b ; b = b->level_chain) + if (b->kind == sk_omp) + { + error ("invalid exit from OpenMP structured block"); + return false; + } + return true; } /* Define a label, specifying the location in the source file. @@ -2367,14 +2490,17 @@ check_goto (tree decl) tree define_label (location_t location, tree name) { - tree decl = lookup_label (name); - struct named_label_list *ent; + struct named_label_entry *ent, dummy; struct cp_binding_level *p; + tree decl; timevar_push (TV_NAME_LOOKUP); - for (ent = named_labels; ent; ent = ent->next) - if (ent->label_decl == decl) - break; + + decl = lookup_label (name); + + dummy.label_decl = decl; + ent = (struct named_label_entry *) htab_find (named_labels, &dummy); + gcc_assert (ent != NULL); /* After labels, make any new cleanups in the function go into their own new (temporary) binding contour. */ @@ -2390,16 +2516,19 @@ define_label (location_t location, tree name) error ("duplicate label %qD", decl); else { + struct named_label_use_entry *use; + /* Mark label as having been defined. */ DECL_INITIAL (decl) = error_mark_node; /* Say where in the source. */ DECL_SOURCE_LOCATION (decl) = location; - if (ent) - { - ent->names_in_scope = current_binding_level->names; - ent->binding_level = current_binding_level; - } - check_previous_gotos (decl); + + ent->binding_level = current_binding_level; + ent->names_in_scope = current_binding_level->names; + + for (use = ent->uses; use ; use = use->next) + check_previous_goto (decl, use); + ent->uses = NULL; } POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, decl); @@ -2486,11 +2615,12 @@ finish_case_label (tree low_value, tree high_value) if (cond && TREE_CODE (cond) == TREE_LIST) cond = TREE_VALUE (cond); + if (!check_switch_goto (switch_stack->level)) + return error_mark_node; + r = c_add_case_label (switch_stack->cases, cond, TREE_TYPE (cond), low_value, high_value); - check_switch_goto (switch_stack->level); - /* After labels, make any new cleanups in the function go into their own new (temporary) binding contour. */ for (p = current_binding_level; @@ -10589,7 +10719,6 @@ save_function_data (tree decl) /* Clear out the bits we don't need. */ f->base.x_stmt_tree.x_cur_stmt_list = NULL_TREE; - f->x_named_label_uses = NULL; f->bindings = NULL; f->x_local_names = NULL; } @@ -10955,7 +11084,6 @@ finish_function (int flags) } /* Clear out the bits we don't need. */ local_names = NULL; - named_label_uses = NULL; /* We're leaving the context of this function, so zap cfun. It's still in DECL_STRUCT_FUNCTION, and we'll restore it in tree_rest_of_compilation. */ diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 52cef59bb95..ebf8a3365ed 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -1278,6 +1278,7 @@ begin_scope (scope_kind kind, tree entity) case sk_for: case sk_class: case sk_function_parms: + case sk_omp: scope->keep = keep_next_level_flag; break; diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index 12cb697f32b..20c82255a4d 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -106,7 +106,7 @@ typedef enum scope_kind { contents to zero, and the default scope kind is "sk_block". */ sk_cleanup, /* A scope for (pseudo-)scope for cleanup. It is - peusdo in that it is transparent to name lookup + pseudo in that it is transparent to name lookup activities. */ sk_try, /* A try-block. */ sk_catch, /* A catch-block. */ @@ -117,10 +117,11 @@ typedef enum scope_kind { sk_namespace, /* The scope containing the members of a namespace, including the global scope. */ sk_template_parms, /* A scope for template parameters. */ - sk_template_spec /* Like sk_template_parms, but for an explicit + sk_template_spec, /* Like sk_template_parms, but for an explicit specialization. Since, by definition, an explicit specialization is introduced by "template <>", this scope is always empty. */ + sk_omp /* An OpenMP structured block. */ } scope_kind; /* The scope where the class/struct/union/enum tag applies. */ diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index ffec8f2fddd..b5c7fc011a5 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1293,12 +1293,21 @@ typedef struct cp_parser GTY(()) /* TRUE if we are presently parsing a template-argument-list. */ bool in_template_argument_list_p; - /* TRUE if we are presently parsing the body of an - iteration-statement. */ - bool in_iteration_statement_p; - - /* TRUE if we are presently parsing the body of a switch - statement. */ + /* Set to IN_ITERATION_STMT if parsing an iteration-statement, + to IN_OMP_BLOCK if parsing OpenMP structured block and + IN_OMP_FOR if parsing OpenMP loop. If parsing a switch statement, + this is bitwise ORed with IN_SWITCH_STMT, unless parsing an + iteration-statement, OpenMP block or loop within that switch. */ +#define IN_SWITCH_STMT 1 +#define IN_ITERATION_STMT 2 +#define IN_OMP_BLOCK 4 +#define IN_OMP_FOR 8 + unsigned char in_statement; + + /* TRUE if we are presently parsing the body of a switch statement. + Note that this doesn't quite overlap with in_statement above. + The difference relates to giving the right sets of error messages: + "case not in switch" vs "break statement used with OpenMP...". */ bool in_switch_statement_p; /* TRUE if we are parsing a type-id in an expression context. In @@ -2420,6 +2429,17 @@ cp_parser_skip_to_pragma_eol (cp_parser* parser, cp_token *pragma_tok) cp_lexer_purge_tokens_after (parser->lexer, pragma_tok); } +/* Require pragma end of line, resyncing with it as necessary. The + arguments are as for cp_parser_skip_to_pragma_eol. */ + +static void +cp_parser_require_pragma_eol (cp_parser *parser, cp_token *pragma_tok) +{ + parser->lexer->in_pragma = false; + if (!cp_parser_require (parser, CPP_PRAGMA_EOL, "end of line")) + cp_parser_skip_to_pragma_eol (parser, pragma_tok); +} + /* This is a simple wrapper around make_typename_type. When the id is an unresolved identifier node, we can provide a superior diagnostic using cp_parser_diagnose_invalid_type_name. */ @@ -2489,7 +2509,7 @@ cp_parser_new (void) parser->in_template_argument_list_p = false; /* We are not in an iteration statement. */ - parser->in_iteration_statement_p = false; + parser->in_statement = 0; /* We are not in a switch statement. */ parser->in_switch_statement_p = false; @@ -6413,15 +6433,19 @@ cp_parser_selection_statement (cp_parser* parser) else { bool in_switch_statement_p; + unsigned char in_statement; /* Add the condition. */ finish_switch_cond (condition, statement); /* Parse the body of the switch-statement. */ in_switch_statement_p = parser->in_switch_statement_p; + in_statement = parser->in_statement; parser->in_switch_statement_p = true; + parser->in_statement |= IN_SWITCH_STMT; cp_parser_implicitly_scoped_statement (parser); parser->in_switch_statement_p = in_switch_statement_p; + parser->in_statement = in_statement; /* Now we're all done with the switch-statement. */ finish_switch_stmt (statement); @@ -6552,8 +6576,7 @@ cp_parser_iteration_statement (cp_parser* parser) cp_token *token; enum rid keyword; tree statement; - bool in_iteration_statement_p; - + unsigned char in_statement; /* Peek at the next token. */ token = cp_parser_require (parser, CPP_KEYWORD, "iteration-statement"); @@ -6562,7 +6585,7 @@ cp_parser_iteration_statement (cp_parser* parser) /* Remember whether or not we are already within an iteration statement. */ - in_iteration_statement_p = parser->in_iteration_statement_p; + in_statement = parser->in_statement; /* See what kind of keyword it is. */ keyword = token->keyword; @@ -6582,9 +6605,9 @@ cp_parser_iteration_statement (cp_parser* parser) /* Look for the `)'. */ cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); /* Parse the dependent statement. */ - parser->in_iteration_statement_p = true; + parser->in_statement = IN_ITERATION_STMT; cp_parser_already_scoped_statement (parser); - parser->in_iteration_statement_p = in_iteration_statement_p; + parser->in_statement = in_statement; /* We're done with the while-statement. */ finish_while_stmt (statement); } @@ -6597,9 +6620,9 @@ cp_parser_iteration_statement (cp_parser* parser) /* Begin the do-statement. */ statement = begin_do_stmt (); /* Parse the body of the do-statement. */ - parser->in_iteration_statement_p = true; + parser->in_statement = IN_ITERATION_STMT; cp_parser_implicitly_scoped_statement (parser); - parser->in_iteration_statement_p = in_iteration_statement_p; + parser->in_statement = in_statement; finish_do_body (statement); /* Look for the `while' keyword. */ cp_parser_require_keyword (parser, RID_WHILE, "`while'"); @@ -6644,9 +6667,9 @@ cp_parser_iteration_statement (cp_parser* parser) cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); /* Parse the body of the for-statement. */ - parser->in_iteration_statement_p = true; + parser->in_statement = IN_ITERATION_STMT; cp_parser_already_scoped_statement (parser); - parser->in_iteration_statement_p = in_iteration_statement_p; + parser->in_statement = in_statement; /* We're done with the for-statement. */ finish_for_stmt (statement); @@ -6726,25 +6749,42 @@ cp_parser_jump_statement (cp_parser* parser) switch (keyword) { case RID_BREAK: - if (!parser->in_switch_statement_p - && !parser->in_iteration_statement_p) + switch (parser->in_statement) { + case 0: error ("break statement not within loop or switch"); - statement = error_mark_node; + break; + default: + gcc_assert ((parser->in_statement & IN_SWITCH_STMT) + || parser->in_statement == IN_ITERATION_STMT); + statement = finish_break_stmt (); + break; + case IN_OMP_BLOCK: + error ("invalid exit from OpenMP structured block"); + break; + case IN_OMP_FOR: + error ("break statement used with OpenMP for loop"); + break; } - else - statement = finish_break_stmt (); cp_parser_require (parser, CPP_SEMICOLON, "%<;%>"); break; case RID_CONTINUE: - if (!parser->in_iteration_statement_p) + switch (parser->in_statement & ~IN_SWITCH_STMT) { + case 0: error ("continue statement not within a loop"); - statement = error_mark_node; + break; + case IN_ITERATION_STMT: + case IN_OMP_FOR: + statement = finish_continue_stmt (); + break; + case IN_OMP_BLOCK: + error ("invalid exit from OpenMP structured block"); + break; + default: + gcc_unreachable (); } - else - statement = finish_continue_stmt (); cp_parser_require (parser, CPP_SEMICOLON, "%<;%>"); break; @@ -17590,76 +17630,1322 @@ cp_parser_objc_statement (cp_parser * parser) { return error_mark_node; } -/* The parser. */ + +/* OpenMP 2.5 parsing routines. */ + +/* All OpenMP clauses. OpenMP 2.5. */ +typedef enum pragma_omp_clause { + PRAGMA_OMP_CLAUSE_NONE = 0, + + PRAGMA_OMP_CLAUSE_COPYIN, + PRAGMA_OMP_CLAUSE_COPYPRIVATE, + PRAGMA_OMP_CLAUSE_DEFAULT, + PRAGMA_OMP_CLAUSE_FIRSTPRIVATE, + PRAGMA_OMP_CLAUSE_IF, + PRAGMA_OMP_CLAUSE_LASTPRIVATE, + PRAGMA_OMP_CLAUSE_NOWAIT, + PRAGMA_OMP_CLAUSE_NUM_THREADS, + PRAGMA_OMP_CLAUSE_ORDERED, + PRAGMA_OMP_CLAUSE_PRIVATE, + PRAGMA_OMP_CLAUSE_REDUCTION, + PRAGMA_OMP_CLAUSE_SCHEDULE, + PRAGMA_OMP_CLAUSE_SHARED +} pragma_omp_clause; + +/* Returns name of the next clause. + If the clause is not recognized PRAGMA_OMP_CLAUSE_NONE is returned and + the token is not consumed. Otherwise appropriate pragma_omp_clause is + returned and the token is consumed. */ + +static pragma_omp_clause +cp_parser_omp_clause_name (cp_parser *parser) +{ + pragma_omp_clause result = PRAGMA_OMP_CLAUSE_NONE; + + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_IF)) + result = PRAGMA_OMP_CLAUSE_IF; + else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_DEFAULT)) + result = PRAGMA_OMP_CLAUSE_DEFAULT; + else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_PRIVATE)) + result = PRAGMA_OMP_CLAUSE_PRIVATE; + else if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->value; + const char *p = IDENTIFIER_POINTER (id); + + switch (p[0]) + { + case 'c': + if (!strcmp ("copyin", p)) + result = PRAGMA_OMP_CLAUSE_COPYIN; + else if (!strcmp ("copyprivate", p)) + result = PRAGMA_OMP_CLAUSE_COPYPRIVATE; + break; + case 'f': + if (!strcmp ("firstprivate", p)) + result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE; + break; + case 'l': + if (!strcmp ("lastprivate", p)) + result = PRAGMA_OMP_CLAUSE_LASTPRIVATE; + break; + case 'n': + if (!strcmp ("nowait", p)) + result = PRAGMA_OMP_CLAUSE_NOWAIT; + else if (!strcmp ("num_threads", p)) + result = PRAGMA_OMP_CLAUSE_NUM_THREADS; + break; + case 'o': + if (!strcmp ("ordered", p)) + result = PRAGMA_OMP_CLAUSE_ORDERED; + break; + case 'r': + if (!strcmp ("reduction", p)) + result = PRAGMA_OMP_CLAUSE_REDUCTION; + break; + case 's': + if (!strcmp ("schedule", p)) + result = PRAGMA_OMP_CLAUSE_SCHEDULE; + else if (!strcmp ("shared", p)) + result = PRAGMA_OMP_CLAUSE_SHARED; + break; + } + } -static GTY (()) cp_parser *the_parser; + if (result != PRAGMA_OMP_CLAUSE_NONE) + cp_lexer_consume_token (parser->lexer); - -/* Special handling for the first token or line in the file. The first - thing in the file might be #pragma GCC pch_preprocess, which loads a - PCH file, which is a GC collection point. So we need to handle this - first pragma without benefit of an existing lexer structure. + return result; +} - Always returns one token to the caller in *FIRST_TOKEN. This is - either the true first token of the file, or the first token after - the initial pragma. */ +/* Validate that a clause of the given type does not already exist. */ static void -cp_parser_initial_pragma (cp_token *first_token) +check_no_duplicate_clause (tree clauses, enum tree_code code, const char *name) { - tree name = NULL; + tree c; - cp_lexer_get_preprocessor_token (NULL, first_token); - if (first_token->pragma_kind != PRAGMA_GCC_PCH_PREPROCESS) - return; + for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == code) + { + error ("too many %qs clauses", name); + break; + } +} - cp_lexer_get_preprocessor_token (NULL, first_token); - if (first_token->type == CPP_STRING) +/* OpenMP 2.5: + variable-list: + identifier + variable-list , identifier + + In addition, we match a closing parenthesis. An opening parenthesis + will have been consumed by the caller. + + If KIND is nonzero, create the appropriate node and install the decl + in OMP_CLAUSE_DECL and add the node to the head of the list. + + If KIND is zero, create a TREE_LIST with the decl in TREE_PURPOSE; + return the list created. */ + +static tree +cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, + tree list) +{ + while (1) { - name = first_token->value; + tree name, decl; - cp_lexer_get_preprocessor_token (NULL, first_token); - if (first_token->type != CPP_PRAGMA_EOL) - error ("junk at end of %<#pragma GCC pch_preprocess%>"); + name = cp_parser_id_expression (parser, /*template_p=*/false, + /*check_dependency_p=*/true, + /*template_p=*/NULL, + /*declarator_p=*/false); + if (name == error_mark_node) + goto skip_comma; + + decl = cp_parser_lookup_name_simple (parser, name); + if (decl == error_mark_node) + cp_parser_name_lookup_error (parser, name, decl, NULL); + else if (kind != 0) + { + tree u = build_omp_clause (kind); + OMP_CLAUSE_DECL (u) = decl; + OMP_CLAUSE_CHAIN (u) = list; + list = u; + } + else + list = tree_cons (decl, NULL_TREE, list); + + get_comma: + if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)) + break; + cp_lexer_consume_token (parser->lexer); + } + + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'")) + { + int ending; + + /* Try to resync to an unnested comma. Copied from + cp_parser_parenthesized_expression_list. */ + skip_comma: + ending = cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/true, + /*consume_paren=*/true); + if (ending < 0) + goto get_comma; + } + + return list; +} + +/* Similarly, but expect leading and trailing parenthesis. This is a very + common case for omp clauses. */ + +static tree +cp_parser_omp_var_list (cp_parser *parser, enum omp_clause_code kind, tree list) +{ + if (cp_parser_require (parser, CPP_OPEN_PAREN, "`('")) + return cp_parser_omp_var_list_no_open (parser, kind, list); + return list; +} + +/* OpenMP 2.5: + default ( shared | none ) */ + +static tree +cp_parser_omp_clause_default (cp_parser *parser, tree list) +{ + enum omp_clause_default_kind kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED; + tree c; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, "`('")) + return list; + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->value; + const char *p = IDENTIFIER_POINTER (id); + + switch (p[0]) + { + case 'n': + if (strcmp ("none", p) != 0) + goto invalid_kind; + kind = OMP_CLAUSE_DEFAULT_NONE; + break; + + case 's': + if (strcmp ("shared", p) != 0) + goto invalid_kind; + kind = OMP_CLAUSE_DEFAULT_SHARED; + break; + + default: + goto invalid_kind; + } + + cp_lexer_consume_token (parser->lexer); } else - error ("expected string literal"); + { + invalid_kind: + cp_parser_error (parser, "expected % or %"); + } - /* Skip to the end of the pragma. */ - while (first_token->type != CPP_PRAGMA_EOL && first_token->type != CPP_EOF) - cp_lexer_get_preprocessor_token (NULL, first_token); + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'")) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + if (kind == OMP_CLAUSE_DEFAULT_UNSPECIFIED) + return list; - /* Read one more token to return to our caller. */ - cp_lexer_get_preprocessor_token (NULL, first_token); + check_no_duplicate_clause (list, OMP_CLAUSE_DEFAULT, "default"); + c = build_omp_clause (OMP_CLAUSE_DEFAULT); + OMP_CLAUSE_CHAIN (c) = list; + OMP_CLAUSE_DEFAULT_KIND (c) = kind; - /* Now actually load the PCH file. */ - if (name) - c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name)); + return c; } -/* Normal parsing of a pragma token. Here we can (and must) use the - regular lexer. */ +/* OpenMP 2.5: + if ( expression ) */ -static bool -cp_parser_pragma (cp_parser *parser, enum pragma_context context ATTRIBUTE_UNUSED) +static tree +cp_parser_omp_clause_if (cp_parser *parser, tree list) { - cp_token *pragma_tok; - unsigned int id; + tree t, c; - pragma_tok = cp_lexer_consume_token (parser->lexer); - gcc_assert (pragma_tok->type == CPP_PRAGMA); - parser->lexer->in_pragma = true; + if (!cp_parser_require (parser, CPP_OPEN_PAREN, "`('")) + return list; - id = pragma_tok->pragma_kind; - switch (id) + t = cp_parser_condition (parser); + + if (t == error_mark_node + || !cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'")) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + check_no_duplicate_clause (list, OMP_CLAUSE_IF, "if"); + + c = build_omp_clause (OMP_CLAUSE_IF); + OMP_CLAUSE_IF_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 2.5: + nowait */ + +static tree +cp_parser_omp_clause_nowait (cp_parser *parser ATTRIBUTE_UNUSED, tree list) +{ + tree c; + + check_no_duplicate_clause (list, OMP_CLAUSE_NOWAIT, "nowait"); + + c = build_omp_clause (OMP_CLAUSE_NOWAIT); + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 2.5: + num_threads ( expression ) */ + +static tree +cp_parser_omp_clause_num_threads (cp_parser *parser, tree list) +{ + tree t, c; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, "`('")) + return list; + + t = cp_parser_expression (parser, false); + + if (t == error_mark_node + || !cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'")) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + check_no_duplicate_clause (list, OMP_CLAUSE_NUM_THREADS, "num_threads"); + + c = build_omp_clause (OMP_CLAUSE_NUM_THREADS); + OMP_CLAUSE_NUM_THREADS_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 2.5: + ordered */ + +static tree +cp_parser_omp_clause_ordered (cp_parser *parser ATTRIBUTE_UNUSED, tree list) +{ + tree c; + + check_no_duplicate_clause (list, OMP_CLAUSE_ORDERED, "ordered"); + + c = build_omp_clause (OMP_CLAUSE_ORDERED); + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 2.5: + reduction ( reduction-operator : variable-list ) + + reduction-operator: + One of: + * - & ^ | && || */ + +static tree +cp_parser_omp_clause_reduction (cp_parser *parser, tree list) +{ + enum tree_code code; + tree nlist, c; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, "`('")) + return list; + + switch (cp_lexer_peek_token (parser->lexer)->type) { - case PRAGMA_GCC_PCH_PREPROCESS: - error ("%<#pragma GCC pch_preprocess%> must be first"); + case CPP_PLUS: + code = PLUS_EXPR; + break; + case CPP_MULT: + code = MULT_EXPR; + break; + case CPP_MINUS: + code = MINUS_EXPR; + break; + case CPP_AND: + code = BIT_AND_EXPR; + break; + case CPP_XOR: + code = BIT_XOR_EXPR; + break; + case CPP_OR: + code = BIT_IOR_EXPR; + break; + case CPP_AND_AND: + code = TRUTH_ANDIF_EXPR; + break; + case CPP_OR_OR: + code = TRUTH_ORIF_EXPR; break; - default: - gcc_assert (id >= PRAGMA_FIRST_EXTERNAL); - c_invoke_pragma_handler (id); + cp_parser_error (parser, "`+', `*', `-', `&', `^', `|', `&&', or `||'"); + resync_fail: + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; + } + cp_lexer_consume_token (parser->lexer); + + if (!cp_parser_require (parser, CPP_COLON, "`:'")) + goto resync_fail; + + nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_REDUCTION, list); + for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_REDUCTION_CODE (c) = code; + + return nlist; +} + +/* OpenMP 2.5: + schedule ( schedule-kind ) + schedule ( schedule-kind , expression ) + + schedule-kind: + static | dynamic | guided | runtime +*/ + +static tree +cp_parser_omp_clause_schedule (cp_parser *parser, tree list) +{ + tree c, t; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + c = build_omp_clause (OMP_CLAUSE_SCHEDULE); + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->value; + const char *p = IDENTIFIER_POINTER (id); + + switch (p[0]) + { + case 'd': + if (strcmp ("dynamic", p) != 0) + goto invalid_kind; + OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_DYNAMIC; + break; + + case 'g': + if (strcmp ("guided", p) != 0) + goto invalid_kind; + OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_GUIDED; + break; + + case 'r': + if (strcmp ("runtime", p) != 0) + goto invalid_kind; + OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_RUNTIME; + break; + + default: + goto invalid_kind; + } + } + else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_STATIC)) + OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_STATIC; + else + goto invalid_kind; + cp_lexer_consume_token (parser->lexer); + + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + { + cp_lexer_consume_token (parser->lexer); + + t = cp_parser_assignment_expression (parser, false); + + if (t == error_mark_node) + goto resync_fail; + else if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_RUNTIME) + error ("schedule % does not take " + "a % parameter"); + else + OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c) = t; + + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'")) + goto resync_fail; + } + else if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`,' or `)'")) + goto resync_fail; + + check_no_duplicate_clause (list, OMP_CLAUSE_SCHEDULE, "schedule"); + OMP_CLAUSE_CHAIN (c) = list; + return c; + + invalid_kind: + cp_parser_error (parser, "invalid schedule kind"); + resync_fail: + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; +} + +/* Parse all OpenMP clauses. The set clauses allowed by the directive + is a bitmask in MASK. Return the list of clauses found; the result + of clause default goes in *pdefault. */ + +static tree +cp_parser_omp_all_clauses (cp_parser *parser, unsigned int mask, + const char *where, cp_token *pragma_tok) +{ + tree clauses = NULL; + + while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) + { + pragma_omp_clause c_kind = cp_parser_omp_clause_name (parser); + const char *c_name; + tree prev = clauses; + + switch (c_kind) + { + case PRAGMA_OMP_CLAUSE_COPYIN: + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_COPYIN, clauses); + c_name = "copyin"; + break; + case PRAGMA_OMP_CLAUSE_COPYPRIVATE: + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_COPYPRIVATE, + clauses); + c_name = "copyprivate"; + break; + case PRAGMA_OMP_CLAUSE_DEFAULT: + clauses = cp_parser_omp_clause_default (parser, clauses); + c_name = "default"; + break; + case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE: + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FIRSTPRIVATE, + clauses); + c_name = "firstprivate"; + break; + case PRAGMA_OMP_CLAUSE_IF: + clauses = cp_parser_omp_clause_if (parser, clauses); + c_name = "if"; + break; + case PRAGMA_OMP_CLAUSE_LASTPRIVATE: + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_LASTPRIVATE, + clauses); + c_name = "lastprivate"; + break; + case PRAGMA_OMP_CLAUSE_NOWAIT: + clauses = cp_parser_omp_clause_nowait (parser, clauses); + c_name = "nowait"; + break; + case PRAGMA_OMP_CLAUSE_NUM_THREADS: + clauses = cp_parser_omp_clause_num_threads (parser, clauses); + c_name = "num_threads"; + break; + case PRAGMA_OMP_CLAUSE_ORDERED: + clauses = cp_parser_omp_clause_ordered (parser, clauses); + c_name = "ordered"; + break; + case PRAGMA_OMP_CLAUSE_PRIVATE: + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_PRIVATE, + clauses); + c_name = "private"; + break; + case PRAGMA_OMP_CLAUSE_REDUCTION: + clauses = cp_parser_omp_clause_reduction (parser, clauses); + c_name = "reduction"; + break; + case PRAGMA_OMP_CLAUSE_SCHEDULE: + clauses = cp_parser_omp_clause_schedule (parser, clauses); + c_name = "schedule"; + break; + case PRAGMA_OMP_CLAUSE_SHARED: + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_SHARED, + clauses); + c_name = "shared"; + break; + default: + cp_parser_error (parser, "expected %<#pragma omp%> clause"); + goto saw_error; + } + + if (((mask >> c_kind) & 1) == 0) + { + /* Remove the invalid clause(s) from the list to avoid + confusing the rest of the compiler. */ + clauses = prev; + error ("%qs is not valid for %qs", c_name, where); + } + } + saw_error: + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return finish_omp_clauses (clauses); +} + +/* OpenMP 2.5: + structured-block: + statement + + In practice, we're also interested in adding the statement to an + outer node. So it is convenient if we work around the fact that + cp_parser_statement calls add_stmt. */ + +static unsigned +cp_parser_begin_omp_structured_block (cp_parser *parser) +{ + unsigned save = parser->in_statement; + + /* Only move the values to IN_OMP_BLOCK if they weren't false. + This preserves the "not within loop or switch" style error messages + for nonsense cases like + void foo() { + #pragma omp single + break; + } + */ + if (parser->in_statement) + parser->in_statement = IN_OMP_BLOCK; + + return save; +} + +static void +cp_parser_end_omp_structured_block (cp_parser *parser, unsigned save) +{ + parser->in_statement = save; +} + +static tree +cp_parser_omp_structured_block (cp_parser *parser) +{ + tree stmt = begin_omp_structured_block (); + unsigned int save = cp_parser_begin_omp_structured_block (parser); + + cp_parser_statement (parser, NULL_TREE, false); + + cp_parser_end_omp_structured_block (parser, save); + return finish_omp_structured_block (stmt); +} + +/* OpenMP 2.5: + # pragma omp atomic new-line + expression-stmt + + expression-stmt: + x binop= expr | x++ | ++x | x-- | --x + binop: + +, *, -, /, &, ^, |, <<, >> + + where x is an lvalue expression with scalar type. */ + +static void +cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok) +{ + tree lhs, rhs; + enum tree_code code; + + cp_parser_require_pragma_eol (parser, pragma_tok); + + lhs = cp_parser_unary_expression (parser, /*address_p=*/false, + /*cast_p=*/false); + switch (TREE_CODE (lhs)) + { + case ERROR_MARK: + goto saw_error; + + case PREINCREMENT_EXPR: + case POSTINCREMENT_EXPR: + lhs = TREE_OPERAND (lhs, 0); + code = PLUS_EXPR; + rhs = integer_one_node; + break; + + case PREDECREMENT_EXPR: + case POSTDECREMENT_EXPR: + lhs = TREE_OPERAND (lhs, 0); + code = MINUS_EXPR; + rhs = integer_one_node; + break; + + default: + switch (cp_lexer_peek_token (parser->lexer)->type) + { + case CPP_MULT_EQ: + code = MULT_EXPR; + break; + case CPP_DIV_EQ: + code = TRUNC_DIV_EXPR; + break; + case CPP_PLUS_EQ: + code = PLUS_EXPR; + break; + case CPP_MINUS_EQ: + code = MINUS_EXPR; + break; + case CPP_LSHIFT_EQ: + code = LSHIFT_EXPR; + break; + case CPP_RSHIFT_EQ: + code = RSHIFT_EXPR; + break; + case CPP_AND_EQ: + code = BIT_AND_EXPR; + break; + case CPP_OR_EQ: + code = BIT_IOR_EXPR; + break; + case CPP_XOR_EQ: + code = BIT_XOR_EXPR; + break; + default: + cp_parser_error (parser, + "invalid operator for %<#pragma omp atomic%>"); + goto saw_error; + } + cp_lexer_consume_token (parser->lexer); + + rhs = cp_parser_expression (parser, false); + if (rhs == error_mark_node) + goto saw_error; + break; + } + finish_omp_atomic (code, lhs, rhs); + cp_parser_consume_semicolon_at_end_of_statement (parser); + return; + + saw_error: + cp_parser_skip_to_end_of_block_or_statement (parser); +} + + +/* OpenMP 2.5: + # pragma omp barrier new-line +*/ + +static void +cp_parser_omp_barrier (cp_parser *parser, cp_token *pragma_tok) +{ + cp_parser_require_pragma_eol (parser, pragma_tok); + finish_omp_barrier (); +} + +/* OpenMP 2.5: + # pragma omp critical [(name)] new-line + structured-block +*/ + +static tree +cp_parser_omp_critical (cp_parser *parser, cp_token *pragma_tok) +{ + tree stmt, name = NULL; + + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + { + cp_lexer_consume_token (parser->lexer); + + name = cp_parser_identifier (parser); + + if (name == error_mark_node + || !cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'")) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + if (name == error_mark_node) + name = NULL; + } + cp_parser_require_pragma_eol (parser, pragma_tok); + + stmt = cp_parser_omp_structured_block (parser); + return c_finish_omp_critical (stmt, name); +} + +/* OpenMP 2.5: + # pragma omp flush flush-vars[opt] new-line + + flush-vars: + ( variable-list ) */ + +static void +cp_parser_omp_flush (cp_parser *parser, cp_token *pragma_tok) +{ + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + (void) cp_parser_omp_var_list (parser, 0, NULL); + cp_parser_require_pragma_eol (parser, pragma_tok); + + finish_omp_flush (); +} + +/* Parse the restricted form of the for statment allowed by OpenMP. */ + +static tree +cp_parser_omp_for_loop (cp_parser *parser) +{ + tree init, cond, incr, body, decl, pre_body; + location_t loc; + + if (!cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)) + { + cp_parser_error (parser, "for statement expected"); + return NULL; + } + loc = cp_lexer_consume_token (parser->lexer)->location; + if (!cp_parser_require (parser, CPP_OPEN_PAREN, "`('")) + return NULL; + + init = decl = NULL; + pre_body = push_stmt_list (); + if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) + { + cp_decl_specifier_seq type_specifiers; + + /* First, try to parse as an initialized declaration. See + cp_parser_condition, from whence the bulk of this is copied. */ + + cp_parser_parse_tentatively (parser); + cp_parser_type_specifier_seq (parser, /*is_condition=*/false, + &type_specifiers); + if (!cp_parser_error_occurred (parser)) + { + tree asm_specification, attributes; + cp_declarator *declarator; + + declarator = cp_parser_declarator (parser, + CP_PARSER_DECLARATOR_NAMED, + /*ctor_dtor_or_conv_p=*/NULL, + /*parenthesized_p=*/NULL, + /*member_p=*/false); + attributes = cp_parser_attributes_opt (parser); + asm_specification = cp_parser_asm_specification_opt (parser); + + cp_parser_require (parser, CPP_EQ, "`='"); + if (cp_parser_parse_definitely (parser)) + { + tree pushed_scope; + + decl = start_decl (declarator, &type_specifiers, + /*initialized_p=*/false, attributes, + /*prefix_attributes=*/NULL_TREE, + &pushed_scope); + + init = cp_parser_assignment_expression (parser, false); + + cp_finish_decl (decl, NULL_TREE, /*init_const_expr_p=*/false, + asm_specification, LOOKUP_ONLYCONVERTING); + + if (pushed_scope) + pop_scope (pushed_scope); + } + } + + /* If parsing as an initialized declaration failed, try again as + a simple expression. */ + if (decl == NULL) + { + cp_parser_abort_tentative_parse (parser); + init = cp_parser_expression (parser, false); + } + } + cp_parser_require (parser, CPP_SEMICOLON, "`;'"); + pre_body = pop_stmt_list (pre_body); + + cond = NULL; + if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) + cond = cp_parser_condition (parser); + cp_parser_require (parser, CPP_SEMICOLON, "`;'"); + + incr = NULL; + if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN)) + incr = cp_parser_expression (parser, false); + + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'")) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + /* Note that we saved the original contents of this flag when we entered + the structured block, and so we don't need to re-save it here. */ + parser->in_statement = IN_OMP_FOR; + + /* Note that the grammar doesn't call for a structured block here, + though the loop as a whole is a structured block. */ + body = push_stmt_list (); + cp_parser_statement (parser, NULL_TREE, false); + body = pop_stmt_list (body); + + return finish_omp_for (loc, decl, init, cond, incr, body, pre_body); +} + +/* OpenMP 2.5: + #pragma omp for for-clause[optseq] new-line + for-loop +*/ + +#define OMP_FOR_CLAUSE_MASK \ + ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (1u << PRAGMA_OMP_CLAUSE_ORDERED) \ + | (1u << PRAGMA_OMP_CLAUSE_SCHEDULE) \ + | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static tree +cp_parser_omp_for (cp_parser *parser, cp_token *pragma_tok) +{ + tree clauses, sb, ret; + unsigned int save; + + clauses = cp_parser_omp_all_clauses (parser, OMP_FOR_CLAUSE_MASK, + "#pragma omp for", pragma_tok); + + sb = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + + ret = cp_parser_omp_for_loop (parser); + if (ret) + OMP_FOR_CLAUSES (ret) = clauses; + + cp_parser_end_omp_structured_block (parser, save); + add_stmt (finish_omp_structured_block (sb)); + + return ret; +} + +/* OpenMP 2.5: + # pragma omp master new-line + structured-block +*/ + +static tree +cp_parser_omp_master (cp_parser *parser, cp_token *pragma_tok) +{ + cp_parser_require_pragma_eol (parser, pragma_tok); + return c_finish_omp_master (cp_parser_omp_structured_block (parser)); +} + +/* OpenMP 2.5: + # pragma omp ordered new-line + structured-block +*/ + +static tree +cp_parser_omp_ordered (cp_parser *parser, cp_token *pragma_tok) +{ + cp_parser_require_pragma_eol (parser, pragma_tok); + return c_finish_omp_ordered (cp_parser_omp_structured_block (parser)); +} + +/* OpenMP 2.5: + + section-scope: + { section-sequence } + + section-sequence: + section-directive[opt] structured-block + section-sequence section-directive structured-block */ + +static tree +cp_parser_omp_sections_scope (cp_parser *parser) +{ + tree stmt, substmt; + bool error_suppress = false; + cp_token *tok; + + if (!cp_parser_require (parser, CPP_OPEN_BRACE, "`{'")) + return NULL_TREE; + + stmt = push_stmt_list (); + + if (cp_lexer_peek_token (parser->lexer)->pragma_kind != PRAGMA_OMP_SECTION) + { + unsigned save; + + substmt = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + + while (1) + { + cp_parser_statement (parser, NULL_TREE, false); + + tok = cp_lexer_peek_token (parser->lexer); + if (tok->pragma_kind == PRAGMA_OMP_SECTION) + break; + if (tok->type == CPP_CLOSE_BRACE) + break; + if (tok->type == CPP_EOF) + break; + } + + cp_parser_end_omp_structured_block (parser, save); + substmt = finish_omp_structured_block (substmt); + substmt = build1 (OMP_SECTION, void_type_node, substmt); + add_stmt (substmt); + } + + while (1) + { + tok = cp_lexer_peek_token (parser->lexer); + if (tok->type == CPP_CLOSE_BRACE) + break; + if (tok->type == CPP_EOF) + break; + + if (tok->pragma_kind == PRAGMA_OMP_SECTION) + { + cp_lexer_consume_token (parser->lexer); + cp_parser_require_pragma_eol (parser, tok); + error_suppress = false; + } + else if (!error_suppress) + { + cp_parser_error (parser, "expected %<#pragma omp section%> or %<}%>"); + error_suppress = true; + } + + substmt = cp_parser_omp_structured_block (parser); + substmt = build1 (OMP_SECTION, void_type_node, substmt); + add_stmt (substmt); + } + cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'"); + + substmt = pop_stmt_list (stmt); + + stmt = make_node (OMP_SECTIONS); + TREE_TYPE (stmt) = void_type_node; + OMP_SECTIONS_BODY (stmt) = substmt; + + add_stmt (stmt); + return stmt; +} + +/* OpenMP 2.5: + # pragma omp sections sections-clause[optseq] newline + sections-scope +*/ + +#define OMP_SECTIONS_CLAUSE_MASK \ + ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static tree +cp_parser_omp_sections (cp_parser *parser, cp_token *pragma_tok) +{ + tree clauses, ret; + + clauses = cp_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK, + "#pragma omp sections", pragma_tok); + + ret = cp_parser_omp_sections_scope (parser); + if (ret) + OMP_SECTIONS_CLAUSES (ret) = clauses; + + return ret; +} + +/* OpenMP 2.5: + # pragma parallel parallel-clause new-line + # pragma parallel for parallel-for-clause new-line + # pragma parallel sections parallel-sections-clause new-line +*/ + +#define OMP_PARALLEL_CLAUSE_MASK \ + ( (1u << PRAGMA_OMP_CLAUSE_IF) \ + | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \ + | (1u << PRAGMA_OMP_CLAUSE_SHARED) \ + | (1u << PRAGMA_OMP_CLAUSE_COPYIN) \ + | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (1u << PRAGMA_OMP_CLAUSE_NUM_THREADS)) + +static tree +cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok) +{ + enum pragma_kind p_kind = PRAGMA_OMP_PARALLEL; + const char *p_name = "#pragma omp parallel"; + tree stmt, clauses, par_clause, ws_clause, block; + unsigned int mask = OMP_PARALLEL_CLAUSE_MASK; + unsigned int save; + + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)) + { + cp_lexer_consume_token (parser->lexer); + p_kind = PRAGMA_OMP_PARALLEL_FOR; + p_name = "#pragma omp parallel for"; + mask |= OMP_FOR_CLAUSE_MASK; + mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT); + } + else if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->value; + const char *p = IDENTIFIER_POINTER (id); + if (strcmp (p, "sections") == 0) + { + cp_lexer_consume_token (parser->lexer); + p_kind = PRAGMA_OMP_PARALLEL_SECTIONS; + p_name = "#pragma omp parallel sections"; + mask |= OMP_SECTIONS_CLAUSE_MASK; + mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT); + } + } + + clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok); + block = begin_omp_parallel (); + save = cp_parser_begin_omp_structured_block (parser); + + switch (p_kind) + { + case PRAGMA_OMP_PARALLEL: + cp_parser_already_scoped_statement (parser); + par_clause = clauses; + break; + + case PRAGMA_OMP_PARALLEL_FOR: + c_split_parallel_clauses (clauses, &par_clause, &ws_clause); + stmt = cp_parser_omp_for_loop (parser); + if (stmt) + OMP_FOR_CLAUSES (stmt) = ws_clause; + break; + + case PRAGMA_OMP_PARALLEL_SECTIONS: + c_split_parallel_clauses (clauses, &par_clause, &ws_clause); + stmt = cp_parser_omp_sections_scope (parser); + if (stmt) + OMP_SECTIONS_CLAUSES (stmt) = ws_clause; + break; + + default: + gcc_unreachable (); + } + + cp_parser_end_omp_structured_block (parser, save); + return finish_omp_parallel (par_clause, block); +} + +/* OpenMP 2.5: + # pragma omp single single-clause[optseq] new-line + structured-block +*/ + +#define OMP_SINGLE_CLAUSE_MASK \ + ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static tree +cp_parser_omp_single (cp_parser *parser, cp_token *pragma_tok) +{ + tree stmt = make_node (OMP_SINGLE); + TREE_TYPE (stmt) = void_type_node; + + OMP_SINGLE_CLAUSES (stmt) + = cp_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK, + "#pragma omp single", pragma_tok); + OMP_SINGLE_BODY (stmt) = cp_parser_omp_structured_block (parser); + + return add_stmt (stmt); +} + +/* OpenMP 2.5: + # pragma omp threadprivate (variable-list) */ + +static void +cp_parser_omp_threadprivate (cp_parser *parser, cp_token *pragma_tok) +{ + tree vars; + + vars = cp_parser_omp_var_list (parser, 0, NULL); + cp_parser_require_pragma_eol (parser, pragma_tok); + + if (!targetm.have_tls) + sorry ("threadprivate variables not supported in this target"); + + finish_omp_threadprivate (vars); +} + +/* Main entry point to OpenMP statement pragmas. */ + +static void +cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok) +{ + tree stmt; + + switch (pragma_tok->pragma_kind) + { + case PRAGMA_OMP_ATOMIC: + cp_parser_omp_atomic (parser, pragma_tok); + return; + case PRAGMA_OMP_CRITICAL: + stmt = cp_parser_omp_critical (parser, pragma_tok); + break; + case PRAGMA_OMP_FOR: + stmt = cp_parser_omp_for (parser, pragma_tok); + break; + case PRAGMA_OMP_MASTER: + stmt = cp_parser_omp_master (parser, pragma_tok); + break; + case PRAGMA_OMP_ORDERED: + stmt = cp_parser_omp_ordered (parser, pragma_tok); + break; + case PRAGMA_OMP_PARALLEL: + stmt = cp_parser_omp_parallel (parser, pragma_tok); + break; + case PRAGMA_OMP_SECTIONS: + stmt = cp_parser_omp_sections (parser, pragma_tok); + break; + case PRAGMA_OMP_SINGLE: + stmt = cp_parser_omp_single (parser, pragma_tok); + break; + default: + gcc_unreachable (); + } + + if (stmt) + SET_EXPR_LOCATION (stmt, pragma_tok->location); +} + +/* The parser. */ + +static GTY (()) cp_parser *the_parser; + + +/* Special handling for the first token or line in the file. The first + thing in the file might be #pragma GCC pch_preprocess, which loads a + PCH file, which is a GC collection point. So we need to handle this + first pragma without benefit of an existing lexer structure. + + Always returns one token to the caller in *FIRST_TOKEN. This is + either the true first token of the file, or the first token after + the initial pragma. */ + +static void +cp_parser_initial_pragma (cp_token *first_token) +{ + tree name = NULL; + + cp_lexer_get_preprocessor_token (NULL, first_token); + if (first_token->pragma_kind != PRAGMA_GCC_PCH_PREPROCESS) + return; + + cp_lexer_get_preprocessor_token (NULL, first_token); + if (first_token->type == CPP_STRING) + { + name = first_token->value; + + cp_lexer_get_preprocessor_token (NULL, first_token); + if (first_token->type != CPP_PRAGMA_EOL) + error ("junk at end of %<#pragma GCC pch_preprocess%>"); + } + else + error ("expected string literal"); + + /* Skip to the end of the pragma. */ + while (first_token->type != CPP_PRAGMA_EOL && first_token->type != CPP_EOF) + cp_lexer_get_preprocessor_token (NULL, first_token); + + /* Read one more token to return to our caller. */ + cp_lexer_get_preprocessor_token (NULL, first_token); + + /* Now actually load the PCH file. */ + if (name) + c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name)); +} + +/* Normal parsing of a pragma token. Here we can (and must) use the + regular lexer. */ + +static bool +cp_parser_pragma (cp_parser *parser, enum pragma_context context) +{ + cp_token *pragma_tok; + unsigned int id; + + pragma_tok = cp_lexer_consume_token (parser->lexer); + gcc_assert (pragma_tok->type == CPP_PRAGMA); + parser->lexer->in_pragma = true; + + id = pragma_tok->pragma_kind; + switch (id) + { + case PRAGMA_GCC_PCH_PREPROCESS: + error ("%<#pragma GCC pch_preprocess%> must be first"); + break; + + case PRAGMA_OMP_BARRIER: + switch (context) + { + case pragma_compound: + cp_parser_omp_barrier (parser, pragma_tok); + return false; + case pragma_stmt: + error ("%<#pragma omp barrier%> may only be " + "used in compound statements"); + break; + default: + goto bad_stmt; + } + break; + + case PRAGMA_OMP_FLUSH: + switch (context) + { + case pragma_compound: + cp_parser_omp_flush (parser, pragma_tok); + return false; + case pragma_stmt: + error ("%<#pragma omp flush%> may only be " + "used in compound statements"); + break; + default: + goto bad_stmt; + } + break; + + case PRAGMA_OMP_THREADPRIVATE: + cp_parser_omp_threadprivate (parser, pragma_tok); + return false; + + case PRAGMA_OMP_ATOMIC: + case PRAGMA_OMP_CRITICAL: + case PRAGMA_OMP_FOR: + case PRAGMA_OMP_MASTER: + case PRAGMA_OMP_ORDERED: + case PRAGMA_OMP_PARALLEL: + case PRAGMA_OMP_SECTIONS: + case PRAGMA_OMP_SINGLE: + if (context == pragma_external) + goto bad_stmt; + cp_parser_omp_construct (parser, pragma_tok); + return true; + + case PRAGMA_OMP_SECTION: + error ("%<#pragma omp section%> may only be used in " + "%<#pragma omp sections%> construct"); + break; + + default: + gcc_assert (id >= PRAGMA_FIRST_EXTERNAL); + c_invoke_pragma_handler (id); + break; + + bad_stmt: + cp_parser_error (parser, "expected declaration specifiers"); break; } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 40c682f93c2..6cb78657eb3 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -8081,6 +8081,47 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) } } +/* Like tsubst_copy, but specifically for OpenMP clauses. */ + +static tree +tsubst_omp_clauses (tree clauses, tree args, tsubst_flags_t complain, + tree in_decl) +{ + tree new_clauses = NULL, nc, oc; + + for (oc = clauses; oc ; oc = OMP_CLAUSE_CHAIN (oc)) + { + nc = copy_node (oc); + OMP_CLAUSE_CHAIN (nc) = new_clauses; + new_clauses = nc; + + switch (OMP_CLAUSE_CODE (nc)) + { + case OMP_CLAUSE_PRIVATE: + case OMP_CLAUSE_SHARED: + case OMP_CLAUSE_FIRSTPRIVATE: + case OMP_CLAUSE_LASTPRIVATE: + case OMP_CLAUSE_REDUCTION: + case OMP_CLAUSE_COPYIN: + case OMP_CLAUSE_COPYPRIVATE: + case OMP_CLAUSE_IF: + case OMP_CLAUSE_NUM_THREADS: + case OMP_CLAUSE_SCHEDULE: + OMP_CLAUSE_OPERAND (nc, 0) + = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain, in_decl); + break; + case OMP_CLAUSE_NOWAIT: + case OMP_CLAUSE_ORDERED: + case OMP_CLAUSE_DEFAULT: + break; + default: + gcc_unreachable (); + } + } + + return finish_omp_clauses (nreverse (new_clauses)); +} + /* Like tsubst_copy_and_build, but unshare TREE_LIST nodes. */ static tree @@ -8400,6 +8441,84 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) tsubst (TREE_TYPE (t), args, complain, NULL_TREE); break; + case OMP_PARALLEL: + tmp = tsubst_omp_clauses (OMP_PARALLEL_CLAUSES (t), + args, complain, in_decl); + stmt = begin_omp_parallel (); + tsubst_expr (OMP_PARALLEL_BODY (t), args, complain, in_decl); + finish_omp_parallel (tmp, stmt); + break; + + case OMP_FOR: + { + tree clauses, decl, init, cond, incr, body, pre_body; + + clauses = tsubst_omp_clauses (OMP_FOR_CLAUSES (t), + args, complain, in_decl); + init = OMP_FOR_INIT (t); + gcc_assert (TREE_CODE (init) == MODIFY_EXPR); + decl = tsubst_expr (TREE_OPERAND (init, 0), args, complain, in_decl); + init = tsubst_expr (TREE_OPERAND (init, 1), args, complain, in_decl); + cond = tsubst_expr (OMP_FOR_COND (t), args, complain, in_decl); + incr = tsubst_expr (OMP_FOR_INCR (t), args, complain, in_decl); + + stmt = begin_omp_structured_block (); + + pre_body = push_stmt_list (); + tsubst_expr (OMP_FOR_PRE_BODY (t), args, complain, in_decl); + pre_body = pop_stmt_list (pre_body); + + body = push_stmt_list (); + tsubst_expr (OMP_FOR_BODY (t), args, complain, in_decl); + body = pop_stmt_list (body); + + t = finish_omp_for (EXPR_LOCATION (t), decl, init, cond, incr, body, + pre_body); + if (t) + OMP_FOR_CLAUSES (t) = clauses; + + add_stmt (finish_omp_structured_block (stmt)); + } + break; + + case OMP_SECTIONS: + case OMP_SINGLE: + tmp = tsubst_omp_clauses (OMP_CLAUSES (t), args, complain, in_decl); + stmt = push_stmt_list (); + tsubst_expr (OMP_BODY (t), args, complain, in_decl); + stmt = pop_stmt_list (stmt); + + t = copy_node (t); + OMP_BODY (t) = stmt; + OMP_CLAUSES (t) = tmp; + add_stmt (t); + break; + + case OMP_SECTION: + case OMP_CRITICAL: + case OMP_MASTER: + case OMP_ORDERED: + stmt = push_stmt_list (); + tsubst_expr (OMP_BODY (t), args, complain, in_decl); + stmt = pop_stmt_list (stmt); + + t = copy_node (t); + OMP_BODY (t) = stmt; + add_stmt (t); + break; + + case OMP_ATOMIC: + { + tree op0, op1; + op0 = tsubst_expr (TREE_OPERAND (t, 0), args, complain, in_decl); + op1 = tsubst_expr (TREE_OPERAND (t, 1), args, complain, in_decl); + if (OMP_ATOMIC_DEPENDENT_P (t)) + c_finish_omp_atomic (OMP_ATOMIC_CODE (t), op0, op1); + else + add_stmt (build2 (OMP_ATOMIC, void_type_node, op0, op1)); + } + break; + default: gcc_assert (!STATEMENT_CODE_P (TREE_CODE (t))); 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 %", 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 %", 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 %", 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 %", + 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 % for %", 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 % after first use", v); + else if (! TREE_STATIC (v) && ! DECL_EXTERNAL (v)) + error ("automatic variable %qE cannot be %", v); + else if (! COMPLETE_TYPE_P (TREE_TYPE (v))) + error ("% %qE has incomplete type", v); + else if (TREE_STATIC (v) && TYPE_P (CP_DECL_CONTEXT (v))) + error ("% %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) { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index b082e5653e4..677fd313f4e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2006-03-09 Diego Novillo + + * gcc/testsuite/g++.dg/gomp: New directory. + * gcc/testsuite/g++.dg/dg.exp: Gather tests in gomp/. + 2006-03-09 Roger Sayle Eric Botcazou diff --git a/gcc/testsuite/g++.dg/dg.exp b/gcc/testsuite/g++.dg/dg.exp index fd69fd72984..5ecb161bee7 100644 --- a/gcc/testsuite/g++.dg/dg.exp +++ b/gcc/testsuite/g++.dg/dg.exp @@ -40,6 +40,7 @@ set tests [prune $tests $srcdir/$subdir/pch/*] set tests [prune $tests $srcdir/$subdir/special/*] set tests [prune $tests $srcdir/$subdir/tls/*] set tests [prune $tests $srcdir/$subdir/vect/*] +set tests [prune $tests $srcdir/$subdir/gomp/*] # Main loop. dg-runtest $tests "" $DEFAULT_CXXFLAGS diff --git a/gcc/testsuite/g++.dg/gomp/atomic-1.C b/gcc/testsuite/g++.dg/gomp/atomic-1.C new file mode 100644 index 00000000000..3e4bc569ba7 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/atomic-1.C @@ -0,0 +1,99 @@ +/* { dg-do compile } */ + +int x; +volatile int y; +volatile unsigned char z; + +void f1(void) +{ + #pragma omp atomic + x++; + #pragma omp atomic + x--; + #pragma omp atomic + ++x; + #pragma omp atomic + --x; + #pragma omp atomic + x += 1; + #pragma omp atomic + x -= y; + #pragma omp atomic + x |= 1; + #pragma omp atomic + x &= 1; + #pragma omp atomic + x ^= 1; + #pragma omp atomic + x *= 3; + #pragma omp atomic + x /= 3; + #pragma omp atomic + x /= 3; + #pragma omp atomic + x <<= 3; + #pragma omp atomic + x >>= 3; +} + +void f2(void) +{ + #pragma omp atomic + y++; + #pragma omp atomic + y--; + #pragma omp atomic + ++y; + #pragma omp atomic + --y; + #pragma omp atomic + y += 1; + #pragma omp atomic + y -= x; + #pragma omp atomic + y |= 1; + #pragma omp atomic + y &= 1; + #pragma omp atomic + y ^= 1; + #pragma omp atomic + y *= 3; + #pragma omp atomic + y /= 3; + #pragma omp atomic + y /= 3; + #pragma omp atomic + y <<= 3; + #pragma omp atomic + y >>= 3; +} + +void f3(void) +{ + #pragma omp atomic + z++; + #pragma omp atomic + z--; + #pragma omp atomic + ++z; + #pragma omp atomic + --z; + #pragma omp atomic + z += 1; + #pragma omp atomic + z |= 1; + #pragma omp atomic + z &= 1; + #pragma omp atomic + z ^= 1; + #pragma omp atomic + z *= 3; + #pragma omp atomic + z /= 3; + #pragma omp atomic + z /= 3; + #pragma omp atomic + z <<= 3; + #pragma omp atomic + z >>= 3; +} diff --git a/gcc/testsuite/g++.dg/gomp/atomic-2.C b/gcc/testsuite/g++.dg/gomp/atomic-2.C new file mode 100644 index 00000000000..720ec9e8ba0 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/atomic-2.C @@ -0,0 +1,23 @@ +/* { dg-do compile } */ + +float x, y; + +void f1(void) +{ + #pragma omp atomic + x++; + #pragma omp atomic + x--; + #pragma omp atomic + ++x; + #pragma omp atomic + --x; + #pragma omp atomic + x += 1; + #pragma omp atomic + x -= y; + #pragma omp atomic + x *= 3; + #pragma omp atomic + x /= 3; +} diff --git a/gcc/testsuite/g++.dg/gomp/atomic-3.C b/gcc/testsuite/g++.dg/gomp/atomic-3.C new file mode 100644 index 00000000000..0c612a16061 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/atomic-3.C @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-gimple" } */ + +int *xyzzy; + +void f1(void) +{ + #pragma omp atomic + xyzzy++; +} + +/* { dg-final { scan-tree-dump-times "xyzzy, 4" 1 "gimple" { target i?86-*-* x86_64-*-* ia64-*-* powerpc*-*-* alpha*-*-* } } } */ +/* { dg-final { cleanup-tree-dump "gimple" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/atomic-4.C b/gcc/testsuite/g++.dg/gomp/atomic-4.C new file mode 100644 index 00000000000..7f27370d535 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/atomic-4.C @@ -0,0 +1,24 @@ +/* { dg-do compile } */ + +int a[4]; +int *p; +struct S { int x; int y[4]; } s; +int *bar(void); + +void f1(void) +{ + #pragma omp atomic + a[4] += 1; + #pragma omp atomic + *p += 1; + #pragma omp atomic + s.x += 1; + #pragma omp atomic + s.y[*p] += 1; + #pragma omp atomic + s.y[*p] *= 42; + #pragma omp atomic + *bar() += 1; + #pragma omp atomic + *bar() *= 42; +} diff --git a/gcc/testsuite/g++.dg/gomp/atomic-5.C b/gcc/testsuite/g++.dg/gomp/atomic-5.C new file mode 100644 index 00000000000..0f750c73d74 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/atomic-5.C @@ -0,0 +1,34 @@ +/* { dg-do compile } */ + +int x; +const int y = 0; +int bar(void); + +void f1(void) +{ + #pragma omp atomic + x %= 2; /* { dg-error "invalid operator" } */ + #pragma omp atomic + x = x + 1; /* { dg-error "invalid operator" } */ + #pragma omp atomic + x = 1; /* { dg-error "invalid operator" } */ + #pragma omp atomic + ++y; /* { dg-error "read-only variable" } */ + #pragma omp atomic + y--; /* { dg-error "read-only variable" } */ + #pragma omp atomic + y += 1; /* { dg-error "read-only variable" } */ + #pragma omp atomic + bar(); /* { dg-error "invalid operator" } */ + #pragma omp atomic + bar() += 1; /* { dg-error "lvalue required" } */ + #pragma omp atomic a /* { dg-error "expected end of line" } */ + x++; + #pragma omp atomic + ; /* { dg-error "expected primary-expression" } */ + #pragma omp atomic + #pragma omp atomic /* { dg-error "not allowed" } */ + ; + /* Check that we didn't get stuck on the pragma eol marker. */ + undef; /* { dg-error "" } */ +} diff --git a/gcc/testsuite/g++.dg/gomp/atomic-6.C b/gcc/testsuite/g++.dg/gomp/atomic-6.C new file mode 100644 index 00000000000..52ac40f2a21 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/atomic-6.C @@ -0,0 +1,11 @@ +// { dg-do compile } +// { dg-options "-w -fopenmp" } + +int x[10], z; +double y[10]; + +void f1(void) +{ + #pragma omp atomic + x[z] /= y[z]; +} diff --git a/gcc/testsuite/g++.dg/gomp/atomic-7.C b/gcc/testsuite/g++.dg/gomp/atomic-7.C new file mode 100644 index 00000000000..612e97f4530 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/atomic-7.C @@ -0,0 +1,23 @@ +/* { dg-do compile } */ + +double x, y; + +void f2(void) +{ + #pragma omp atomic + y++; + #pragma omp atomic + y--; + #pragma omp atomic + ++y; + #pragma omp atomic + --y; + #pragma omp atomic + y += 1; + #pragma omp atomic + y -= x; + #pragma omp atomic + y *= 3; + #pragma omp atomic + y /= 3; +} diff --git a/gcc/testsuite/g++.dg/gomp/atomic-8.C b/gcc/testsuite/g++.dg/gomp/atomic-8.C new file mode 100644 index 00000000000..2f04151f0ed --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/atomic-8.C @@ -0,0 +1,21 @@ +/* { dg-do compile } */ + +long double z; + +void f3(void) +{ + #pragma omp atomic + z++; + #pragma omp atomic + z--; + #pragma omp atomic + ++z; + #pragma omp atomic + --z; + #pragma omp atomic + z += 1; + #pragma omp atomic + z *= 3; + #pragma omp atomic + z /= 3; +} diff --git a/gcc/testsuite/g++.dg/gomp/atomic-9.C b/gcc/testsuite/g++.dg/gomp/atomic-9.C new file mode 100644 index 00000000000..128e9df5e4a --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/atomic-9.C @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-gimple" } */ + +volatile int *bar(void); + +void f1(void) +{ + #pragma omp atomic + *bar() += 1; +} + +/* { dg-final { scan-tree-dump-times "__sync_fetch_and_add" 1 "gimple" { target i?86-*-* x86_64-*-* ia64-*-* powerpc*-*-* alpha*-*-* } } } */ +/* { dg-final { cleanup-tree-dump "gimple" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/barrier-1.C b/gcc/testsuite/g++.dg/gomp/barrier-1.C new file mode 100644 index 00000000000..10ca553f94b --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/barrier-1.C @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-gimple" } */ + +void f1(void) +{ + #pragma omp barrier +} + +void f2(bool p) +{ + if (p) + { + #pragma omp barrier + } +} + +/* { dg-final { scan-tree-dump-times "GOMP_barrier" 2 "gimple" } } */ +/* { dg-final { cleanup-tree-dump "gimple" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/barrier-2.C b/gcc/testsuite/g++.dg/gomp/barrier-2.C new file mode 100644 index 00000000000..1d929d26dde --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/barrier-2.C @@ -0,0 +1,12 @@ +// { dg-do compile } + +void f1(void) +{ + #pragma omp barrier a // { dg-error "expected end of line" } +} + +void f3(bool p) +{ + if (p) + #pragma omp barrier // { dg-error "compound statements" } +} // { dg-error "" } diff --git a/gcc/testsuite/g++.dg/gomp/block-0.C b/gcc/testsuite/g++.dg/gomp/block-0.C new file mode 100644 index 00000000000..1be534d59df --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/block-0.C @@ -0,0 +1,33 @@ +// { dg-do compile } +// { dg-options "-fopenmp -fdump-tree-omplower" } + +void bar(); +void foo() +{ + #pragma omp critical + bar (); + #pragma omp master + bar (); + #pragma omp single + bar (); + #pragma omp for + for (int i = 0; i < 10; ++i) + bar (); + #pragma omp sections + { bar(); } + #pragma omp parallel + bar (); + #pragma omp parallel for + for (int i = 0; i < 10; ++i) + bar (); + #pragma omp parallel sections + { + bar (); + bar (); + #pragma omp section + bar (); + } +} + +// { dg-final { scan-tree-dump-times "terminate" 8 "omplower" } } +// { dg-final { cleanup-tree-dump "omplower" } } diff --git a/gcc/testsuite/g++.dg/gomp/block-1.C b/gcc/testsuite/g++.dg/gomp/block-1.C new file mode 100644 index 00000000000..50a8c0e9ead --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/block-1.C @@ -0,0 +1,22 @@ +// { dg-do compile } + +void foo() +{ + bad1: // { dg-error "jump to label" } + #pragma omp parallel + goto bad1; // { dg-error "from here|exits OpenMP" } + + goto bad2; // { dg-error "from here" } + #pragma omp parallel + { + bad2: ; // { dg-error "jump to label|enters OpenMP" } + } + + #pragma omp parallel + { + int i; + goto ok1; + for (i = 0; i < 10; ++i) + { ok1: break; } + } +} diff --git a/gcc/testsuite/g++.dg/gomp/block-10.C b/gcc/testsuite/g++.dg/gomp/block-10.C new file mode 100644 index 00000000000..b273c1f297c --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/block-10.C @@ -0,0 +1,40 @@ +// { dg-do compile } + +void foo(int i) +{ + int j; + switch (i) + { + #pragma omp parallel + { case 0:; } // { dg-error "jump|enters" } + } + switch (i) + { + #pragma omp for + for (j = 0; j < 10; ++ j) + { case 1:; } // { dg-error "jump|enters" } + } + switch (i) + { + #pragma omp critical + { case 2:; } // { dg-error "jump|enters" } + } + switch (i) + { + #pragma omp master + { case 3:; } // { dg-error "jump|enters" } + } + switch (i) + { + #pragma omp sections + { case 4:; // { dg-error "jump|enters" } + #pragma omp section + { case 5:; } // { dg-error "jump|enters" } + } + } + switch (i) + { + #pragma omp ordered + { default:; } // { dg-error "jump|enters" } + } +} diff --git a/gcc/testsuite/g++.dg/gomp/block-11.C b/gcc/testsuite/g++.dg/gomp/block-11.C new file mode 100644 index 00000000000..c2800061b6e --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/block-11.C @@ -0,0 +1,19 @@ +/* PR c++/24516 */ +/* { dg-do compile } */ + +void +bar (int *p) +{ + int m; +#pragma omp parallel for + for (m = 0; m < 1000; ++m) + switch (p[m]) + { + case 1: + p[m] = 2; + break; + default: + p[m] = 3; + break; + } +} diff --git a/gcc/testsuite/g++.dg/gomp/block-2.C b/gcc/testsuite/g++.dg/gomp/block-2.C new file mode 100644 index 00000000000..621a90d7bc4 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/block-2.C @@ -0,0 +1,32 @@ +// { dg-do compile } + +void foo() +{ + int i, j; + + #pragma omp for + for (i = 0; i < 10; ++i) + break; // { dg-error "break" } + + bad1: // { dg-error "jump to label" } + #pragma omp for + for (i = 0; i < 10; ++i) + goto bad1; // { dg-error "from here|exits OpenMP" } + + goto bad2; // { dg-error "from here" } + #pragma omp for + for (i = 0; i < 10; ++i) + { + bad2: ; // { dg-error "jump|enters OpenMP" } + } + + #pragma omp for + for (i = 0; i < 10; ++i) + for (j = 0; j < 10; ++j) + if (i == j) + break; + + #pragma omp for + for (i = 0; i < 10; ++i) + continue; +} diff --git a/gcc/testsuite/g++.dg/gomp/block-3.C b/gcc/testsuite/g++.dg/gomp/block-3.C new file mode 100644 index 00000000000..8e036e45364 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/block-3.C @@ -0,0 +1,57 @@ +// { dg-do compile } + +extern int test(int); +void foo() +{ + int i; + + for (i = 0; i < 10; ++i) + { + #pragma omp sections + { + continue; // { dg-error "invalid exit" } + } + } + + #pragma omp sections + { + #pragma omp section + { bad1: ; } // { dg-error "jump to label" } + #pragma omp section + goto bad1; // { dg-error "from here|enters OpenMP" } + } + + #pragma omp sections + { + goto bad2; // { dg-error "from here" } + } + bad2:; // { dg-error "jump|exits OpenMP" } + + goto bad3; // { dg-error "from here" } + #pragma omp sections + { + bad3: ; // { dg-error "jump|enters OpenMP" } + } + + #pragma omp sections + { + goto ok1; + ok1:; + + #pragma omp section + for (i = 0; i < 10; ++i) + if (test(i)) + break; + else + continue; + + #pragma omp section + switch (i) + { + case 0: + break; + default: + test(i); + } + } +} diff --git a/gcc/testsuite/g++.dg/gomp/block-4.C b/gcc/testsuite/g++.dg/gomp/block-4.C new file mode 100644 index 00000000000..815d36b2e39 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/block-4.C @@ -0,0 +1,9 @@ +// { dg-do compile } + +void foo() +{ + #pragma omp critical + { + return; // { dg-error "invalid exit" } + } +} diff --git a/gcc/testsuite/g++.dg/gomp/block-5.C b/gcc/testsuite/g++.dg/gomp/block-5.C new file mode 100644 index 00000000000..67ed72c8daa --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/block-5.C @@ -0,0 +1,15 @@ +// { dg-do compile } + +void foo() +{ + #pragma omp master + { + goto bad1; // { dg-error "from here" } + } + + #pragma omp master + { + bad1: // { dg-error "jump|exits OpenMP" } + return; // { dg-error "invalid exit" } + } +} diff --git a/gcc/testsuite/g++.dg/gomp/block-6.C b/gcc/testsuite/g++.dg/gomp/block-6.C new file mode 100644 index 00000000000..fa4c5eab5f4 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/block-6.C @@ -0,0 +1,9 @@ +// { dg-do compile } + +void foo() +{ + #pragma omp ordered + { + return; // { dg-error "invalid exit" } + } +} diff --git a/gcc/testsuite/g++.dg/gomp/block-7.C b/gcc/testsuite/g++.dg/gomp/block-7.C new file mode 100644 index 00000000000..802b3b3a383 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/block-7.C @@ -0,0 +1,20 @@ +// { dg-do compile } + +void foo() +{ + int i, j; + for (i = 0; i < 10; ++i) + { + #pragma omp for + for (j = ({ continue; 0; }); // { dg-error "invalid exit" } + j < ({ continue; 10; }); // { dg-error "invalid exit" } + j += ({ continue; 1; })) // { dg-error "invalid exit" } + continue; + + #pragma omp for + for (j = ({ break; 0; }); // { dg-error "invalid exit" } + j < ({ break; 10; }); // { dg-error "invalid exit" } + j += ({ break; 1; })) // { dg-error "invalid exit" } + break; // { dg-error "break" } + } +} diff --git a/gcc/testsuite/g++.dg/gomp/block-8.C b/gcc/testsuite/g++.dg/gomp/block-8.C new file mode 100644 index 00000000000..177acaa28c0 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/block-8.C @@ -0,0 +1,11 @@ +// { dg-do compile } +// PR 24451 + +int foo() +{ + int i; + + #pragma omp parallel for + for (i = 0; i < 10; ++i) + return 0; // { dg-error "invalid exit" } +} diff --git a/gcc/testsuite/g++.dg/gomp/block-9.C b/gcc/testsuite/g++.dg/gomp/block-9.C new file mode 100644 index 00000000000..8012e5a7d46 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/block-9.C @@ -0,0 +1,25 @@ +// { dg-do compile } + +void foo(int i) +{ + int j; + switch (i) + { + #pragma omp parallel + { case 0:; } // { dg-error "jump|enters" } + #pragma omp for + for (j = 0; j < 10; ++ j) + { case 1:; } // { dg-error "jump|enters" } + #pragma omp critical + { case 2:; } // { dg-error "jump|enters" } + #pragma omp master + { case 3:; } // { dg-error "jump|enters" } + #pragma omp sections + { case 4:; // { dg-error "jump|enters" } + #pragma omp section + { case 5:; } // { dg-error "jump|enters" } + } + #pragma omp ordered + { default:; } // { dg-error "jump|enters" } + } +} diff --git a/gcc/testsuite/g++.dg/gomp/clause-1.C b/gcc/testsuite/g++.dg/gomp/clause-1.C new file mode 100644 index 00000000000..76683ecf6ee --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/clause-1.C @@ -0,0 +1,32 @@ +// { dg-do compile } + +struct T +{ + int n; + + void test(); +}; + +void T::test() +{ + #pragma omp parallel private(n) // { dg-error "T::n" } + n = 1; + + #pragma omp parallel shared(n) // { dg-error "T::n" } + n = 1; + + #pragma omp parallel firstprivate(n) // { dg-error "T::n" } + n = 1; + + #pragma omp sections lastprivate(n) // { dg-error "T::n" } + { n = 1; } + + #pragma omp parallel reduction(+:n) // { dg-error "T::n" } + n = 1; + + #pragma omp single copyprivate(n) // { dg-error "T::n" } + n = 1; + + #pragma omp parallel copyin(n) // { dg-error "T::n" } + n = 1; +} diff --git a/gcc/testsuite/g++.dg/gomp/clause-2.C b/gcc/testsuite/g++.dg/gomp/clause-2.C new file mode 100644 index 00000000000..450419ad6cd --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/clause-2.C @@ -0,0 +1,38 @@ +// { dg-do compile } + +struct A { int a; }; +struct B { B(); }; +struct C { C(); C(const C&); }; +struct D { D& operator=(const D&); }; + +class E { private: E(); public: E(int); }; // { dg-error "private" } +class F { private: F(const F&); public: F(); }; // { dg-error "private" } +class G { private: G& operator=(const G&); }; // { dg-error "private" } + +void bar(); +void foo() +{ + A a; B b; C c; D d; E e(0); F f; G g; + + #pragma omp parallel shared(a, b, c, d, e, f, g) + bar(); + + #pragma omp parallel private(a, b, c, d, f, g) + bar(); + #pragma omp parallel private(e) // { dg-error "context" } + bar(); + + #pragma omp parallel firstprivate(a, b, c, d, e, g) + bar(); + #pragma omp parallel firstprivate(f) // { dg-error "context" } + bar(); + + #pragma omp parallel sections lastprivate(a, b, d, c, f) + { bar(); } + #pragma omp parallel sections lastprivate(e) // { dg-error "context" } + { bar(); } + #pragma omp parallel sections lastprivate(g) // { dg-error "context" } + { bar(); } + #pragma omp parallel sections firstprivate(e) lastprivate(e) + { bar(); } +} diff --git a/gcc/testsuite/g++.dg/gomp/clause-3.C b/gcc/testsuite/g++.dg/gomp/clause-3.C new file mode 100644 index 00000000000..6b3d410a933 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/clause-3.C @@ -0,0 +1,94 @@ +// { dg-do compile } +// { dg-require-effective-target tls } + +#define p parallel + +extern void bar (void); +extern char q[]; // { dg-error "has incomplete type" } +int t; +#pragma omp threadprivate (t) + +void +foo (int x) +{ + char *p; + struct S { int i; int j; } s; + char a[32]; + double d; + int i; + const int c = 8; +#pragma omp p shared (x, x) // { dg-error "more than once" } + ; +#pragma omp p private (x) private (x) // { dg-error "more than once" } + ; +#pragma omp p shared (x) firstprivate (x) // { dg-error "more than once" } + ; +#pragma omp p firstprivate (x, x) // { dg-error "more than once" } + ; +#pragma omp p for shared (x) lastprivate (x) // { dg-error "more than once" } + for (i = 0; i < 10; i++) + ; +#pragma omp p for private (x) lastprivate (x) // { dg-error "more than once" } + for (i = 0; i < 10; i++) + ; +#pragma omp p for lastprivate (x, x) // { dg-error "more than once" } + for (i = 0; i < 10; i++) + ; +#pragma omp single private (x) copyprivate (x) // { dg-error "more than once" } + ; +#pragma omp p shared (bar) // { dg-error "is not a variable" } + ; +#pragma omp p private (bar) // { dg-error "is not a variable" } + ; +#pragma omp p firstprivate (bar) // { dg-error "is not a variable" } + ; +#pragma omp p reduction (+:p) // { dg-error "has invalid type for" } + ; +#pragma omp p reduction (*:s) // { dg-error "has invalid type for" } + ; +#pragma omp p reduction (-:a) // { dg-error "has invalid type for" } + ; + d = 0; +#pragma omp p reduction (*:d) + ; +#pragma omp p reduction (|:d) // { dg-error "has invalid type for" } + ; +#pragma omp p reduction (&&:d) // { dg-error "has invalid type for" } + ; +#pragma omp p copyin (d) // { dg-error "must be 'threadprivate'" } + ; +#pragma omp p copyin (x) // { dg-error "must be 'threadprivate'" } + ; +#pragma omp p for firstprivate (x) lastprivate (x) + for (i = 0; i < 10; i++) + ; +#pragma omp p private (q) // { dg-error "unspecified bounds" } + ; +#pragma omp p firstprivate (q) // { dg-error "unspecified bounds" } + ; +#pragma omp p for lastprivate (q) // { dg-error "unspecified bounds" } + for (i = 0; i < 10; i++) + ; +#pragma omp p shared (t) // { dg-error "predetermined 'threadprivate'" } + ; +#pragma omp p private (t) // { dg-error "predetermined 'threadprivate'" } + ; +#pragma omp p firstprivate (t) // { dg-error "predetermined 'threadprivate'" } + ; +#pragma omp p for lastprivate (t) // { dg-error "predetermined 'threadpriv" } + for (i = 0; i < 10; i++) + ; +#pragma omp p reduction (*:t) // { dg-error "predetermined 'threadprivate'" } + ; +#pragma omp p shared (c) // { dg-error "predetermined 'shared'" } + ; +#pragma omp p private (c) // { dg-error "predetermined 'shared'" } + ; +#pragma omp p firstprivate (c) // { dg-error "predetermined 'shared'" } + ; +#pragma omp p for lastprivate (c) // { dg-error "predetermined 'shared'" } + for (i = 0; i < 10; i++) + ; +#pragma omp p reduction (*:c) // { dg-error "predetermined 'shared'" } + ; +} diff --git a/gcc/testsuite/g++.dg/gomp/copyin-1.C b/gcc/testsuite/g++.dg/gomp/copyin-1.C new file mode 100644 index 00000000000..117f82f8134 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/copyin-1.C @@ -0,0 +1,27 @@ +// { dg-do compile } +// { dg-require-effective-target tls } + +int i, j; + +#pragma omp threadprivate (i) + +void bar(void); +void foo(void) +{ + int k; + extern int l; + extern int m; + +#pragma omp threadprivate (m) + + #pragma omp parallel copyin(i) + bar(); + #pragma omp parallel copyin(j) // { dg-error "threadprivate" } + bar(); + #pragma omp parallel copyin(k) // { dg-error "threadprivate" } + bar(); + #pragma omp parallel copyin(l) // { dg-error "threadprivate" } + bar(); + #pragma omp parallel copyin(m) + bar(); +} diff --git a/gcc/testsuite/g++.dg/gomp/critical-1.C b/gcc/testsuite/g++.dg/gomp/critical-1.C new file mode 100644 index 00000000000..bdc7bad7b82 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/critical-1.C @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-omplower" } */ + +extern void bar(int); + +void foo (void) +{ + #pragma omp critical + bar(0); + + /* Note that "name" is in its own namespace, thus this foo is not + the same as the function. */ + #pragma omp critical(foo) + { + bar(1); + bar(2); + } + + #pragma omp critical + #pragma omp critical(foo) + bar(3); +} + +/* { dg-final { scan-tree-dump-times "GOMP_critical_start" 2 "omplower" } } */ +/* { dg-final { scan-tree-dump-times "GOMP_critical_end" 2 "omplower" } } */ +/* { dg-final { scan-tree-dump-times "GOMP_critical_name_start" 2 "omplower" } } */ +/* { dg-final { scan-tree-dump-times "GOMP_critical_name_end" 2 "omplower" } } */ +/* { dg-final { cleanup-tree-dump "omplower" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/critical-2.C b/gcc/testsuite/g++.dg/gomp/critical-2.C new file mode 100644 index 00000000000..37c9c2414d9 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/critical-2.C @@ -0,0 +1,12 @@ +// { dg-do compile } + +void f1(void) +{ + #pragma omp critical a // { dg-error "expected" } + ; + #pragma omp critical ( // { dg-error "expected identifier" } + ; + #pragma omp critical (a // { dg-error "expected .\\)." } + ; + #pragma omp critical (a b) // { dg-error "expected .\\)." } +} // { dg-error "" } diff --git a/gcc/testsuite/g++.dg/gomp/flush-1.C b/gcc/testsuite/g++.dg/gomp/flush-1.C new file mode 100644 index 00000000000..3c6a34bff37 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/flush-1.C @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-gimple" } */ + +void f1(void) +{ + #pragma omp flush +} + +int x; + +void f2(bool p) +{ + int z; + if (p) + { + #pragma omp flush (x) + } + else + { + #pragma omp flush (x, z, p) + } +} + +/* { dg-final { scan-tree-dump-times "__sync_synchronize" 3 "gimple" } } */ +/* { dg-final { cleanup-tree-dump "gimple" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/flush-2.C b/gcc/testsuite/g++.dg/gomp/flush-2.C new file mode 100644 index 00000000000..a5c0df89cc2 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/flush-2.C @@ -0,0 +1,10 @@ +// { dg-do compile } + +void f1(void) +{ + #pragma omp flush a // { dg-error "expected" } + #pragma omp flush ( // { dg-error "expected" } + #pragma omp flush (b // { dg-error "declared|expected" } + #pragma omp flush (c d) // { dg-error "declared|expected" } + #pragma omp flush (e) // { dg-error "declared" } +} diff --git a/gcc/testsuite/g++.dg/gomp/for-1.C b/gcc/testsuite/g++.dg/gomp/for-1.C new file mode 100644 index 00000000000..f8bb9d54727 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/for-1.C @@ -0,0 +1,49 @@ +// { dg-do compile } + +extern void baz(int); +void foo (int j, int k) +{ + int i; + + /* Valid loops. */ + #pragma omp for + for (i = 0; i < 10; i++) + baz (i); + + #pragma omp for + for (i = j; i <= 10; i+=4) + baz (i); + + #pragma omp for + for (i = j; i > 0; i = i - 1) + baz (j); + + #pragma omp for + for (i = j; i >= k; i--) + baz (i); + + // Malformed parallel loops. + #pragma omp for + i = 0; // { dg-error "for statement expected" } + for ( ; i < 10; ) + { + baz (i); + i++; + } + + #pragma omp for + for (i = 0; ; i--) // { dg-error "missing controlling predicate" } + { + if (i >= 10) + break; // { dg-error "break" } + baz (i); + } + + #pragma omp for + for (i = 0; i < 10 && j > 4; i-=3) // { dg-error "invalid controlling predicate" } + baz (i); + + #pragma omp for + for (i = 0; i < 10; i-=3, j+=2) // { dg-error "invalid increment expression" } + baz (i); +} diff --git a/gcc/testsuite/g++.dg/gomp/for-10.C b/gcc/testsuite/g++.dg/gomp/for-10.C new file mode 100644 index 00000000000..f21404249c7 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/for-10.C @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-ompexp" } */ + +extern void bar(int); + +void foo (int n) +{ + int i; + + #pragma omp for schedule(runtime) ordered + for (i = 0; i < n; ++i) + bar(i); +} + +/* { dg-final { scan-tree-dump-times "GOMP_loop_ordered_runtime_start" 1 "ompexp" } } */ +/* { dg-final { scan-tree-dump-times "GOMP_loop_ordered_runtime_next" 1 "ompexp" } } */ +/* { dg-final { cleanup-tree-dump "ompexp" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/for-11.C b/gcc/testsuite/g++.dg/gomp/for-11.C new file mode 100644 index 00000000000..d15576d2fe9 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/for-11.C @@ -0,0 +1,14 @@ +// { dg-do compile } + +extern void baz (int); + +void foo (int j, int k) +{ + #pragma omp for + for (int l = j; l < k; l++) + baz (l); + + #pragma omp for + for (int i = 0, m = 0; m < 10; m++) // { dg-error "" } + baz (m); +} diff --git a/gcc/testsuite/g++.dg/gomp/for-12.C b/gcc/testsuite/g++.dg/gomp/for-12.C new file mode 100644 index 00000000000..98318d7d5ae --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/for-12.C @@ -0,0 +1,12 @@ +int foo (void) +{ + int i, a; + + a = 30; + + #pragma omp parallel for lastprivate (a) + for (i = 0; i < 10; i++) + a = a + i; + + return a; +} diff --git a/gcc/testsuite/g++.dg/gomp/for-13.C b/gcc/testsuite/g++.dg/gomp/for-13.C new file mode 100644 index 00000000000..16e971f1927 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/for-13.C @@ -0,0 +1,18 @@ +// At one point in development, a typo disabled the remapping of the +// for iteration variable as private. + +// { dg-do compile } +// { dg-options "-fopenmp -fdump-tree-lower" } + +extern void bar(int); +void foo(void) +{ + int i; + +#pragma omp parallel for default(none) + for (i = 0; i < 10; i++) + bar(i); +} + +// { dg-final { scan-tree-dump-times "omp_data_o" 0 "lower" } } +// { dg-final { cleanup-tree-dump "lower" } } diff --git a/gcc/testsuite/g++.dg/gomp/for-14.C b/gcc/testsuite/g++.dg/gomp/for-14.C new file mode 100644 index 00000000000..fb264137025 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/for-14.C @@ -0,0 +1,19 @@ +// { dg-do compile } + +extern int printf (const char *, ...); +extern void foo (int *); + +int main (void) +{ + double d = 6; + int i = 1, j = 6, k = 8; +#pragma omp parallel shared(d) private(i) num_threads (4) + { + i = 4; +#pragma omp for lastprivate(j) + for (j = 1; j <= k; j++) + printf ("%s %d %d %d %p %g\n", "Hello, World!", i, j, k, &j, d); + printf ("%s %d %g\n", "Hello, World!", i, d); + } + return 0; +} diff --git a/gcc/testsuite/g++.dg/gomp/for-15.C b/gcc/testsuite/g++.dg/gomp/for-15.C new file mode 100644 index 00000000000..25eea2ad24d --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/for-15.C @@ -0,0 +1,35 @@ +// PR c++/24512 +// { dg-do compile } + +template void foo () +{ +#pragma omp for + for (int i = 0; i < 10; i++); + +#pragma omp for + for (int i = 0; i < 10; i++); + +#pragma omp for + for (T j = 0; j < 10; j++); + +#pragma omp for + for (T j = 0; j < 10; j++); + +#pragma omp parallel for + for (int k = 0; k < 10; k++); + +#pragma omp parallel for + for (int k = 0; k < 10; k++); + +#pragma omp parallel for + for (T l = 0; l < 10; l++); + +#pragma omp parallel for + for (T l = 0; l < 10; l++); +} + +void bar () +{ + foo (); + foo (); +} diff --git a/gcc/testsuite/g++.dg/gomp/for-16.C b/gcc/testsuite/g++.dg/gomp/for-16.C new file mode 100644 index 00000000000..76231751f70 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/for-16.C @@ -0,0 +1,33 @@ +// { dg-do compile } + +template +void foo () +{ +#pragma omp for + for (unsigned int i = 0; i < 10; i++); // { dg-warning "is unsigned" } +#pragma omp for + for (int j = 0; ; j++); // { dg-error "missing controlling predicate" } +#pragma omp for + for (int k = 0; k == 1; k++); // { dg-error "invalid controlling predicate" } +#pragma omp for + for (int l = 0; l < 10; ); // { dg-error "missing increment expression" } +#pragma omp for + for (int m = 0; m < 10; m *= 3); // Error here is emitted only during + // instantiation +#pragma omp for + for (T n = 0; ; n++); // { dg-error "missing controlling predicate" } +#pragma omp for + for (T o = 0; o == 1; o++); // Error here is emitted only during + // instantiation +#pragma omp for + for (T p = 0; p < 10; ); // { dg-error "missing increment expression" } +#pragma omp for + for (T q = 0; q < 10; q *= 3); // Error here is emitted only during + // instantiation +} + +void bar () +{ +#pragma omp for + for (int m = 0; m < 10; m *= 3); // { dg-error "invalid increment expression" } +} diff --git a/gcc/testsuite/g++.dg/gomp/for-17.C b/gcc/testsuite/g++.dg/gomp/for-17.C new file mode 100644 index 00000000000..9634e59c8e3 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/for-17.C @@ -0,0 +1,11 @@ +/* { dg-do compile } */ + +void foo() +{ + long n = 10; + int i; +#pragma omp for + for (i=0; i < n; ++i) ; +#pragma omp for + for (i=0; n > i; ++i) ; +} diff --git a/gcc/testsuite/g++.dg/gomp/for-18.C b/gcc/testsuite/g++.dg/gomp/for-18.C new file mode 100644 index 00000000000..0a505267493 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/for-18.C @@ -0,0 +1,67 @@ +// { dg-do compile } +extern int bar (int); + +void +foo (void) +{ + int j, k = 1, l = 30, m = 4; + long int o = 4; + long long int p = 0; +#pragma omp for + for (j = k; j <= l; j += m - 1) + ; +#pragma omp for + for (j = k; j <= l; j += (m - 1)) + ; +#pragma omp for + for (j = k; j <= l; j += bar (m - 1)) + ; +#pragma omp for + for (j = k; j <= l; j = j + m - 1) + ; +#pragma omp for + for (j = k; j <= l; j = j + (m - 1)) + ; +#pragma omp for + for (j = k; j <= l; j = j + bar (m - 1)) + ; +#pragma omp for + for (j = ({ int n; n = k; n; }); j <= l; j++) + ; +#pragma omp for + for (j = k; j <= ({ int n; n = l; n; }); j++) + ; +#pragma omp for + for (j = k; j <= l; j += ({ int n; n = 1; n; })) + ; +#pragma omp for + for (j = k; j <= l; j += m + 1) + ; +#pragma omp for + for (j = k; j <= l; j += o) + ; +#pragma omp for + for (j = k; j <= l; j = j + o) + ; +#pragma omp for + for (j = k; j <= l; j = o + 1 + j) + ; +#pragma omp for + for (j = k; j <= l; j = o + m + j) + ; +#pragma omp for + for (j = k; j <= l; j += o + p) + ; +#pragma omp for + for (j = k; j <= l; j = j + o + p) + ; +#pragma omp for + for (j = l; j >= k; j -= o) + ; +#pragma omp for + for (j = l; j >= k; j -= p) + ; +#pragma omp for + for (j = l; j >= k; j -= o + p) + ; +} diff --git a/gcc/testsuite/g++.dg/gomp/for-2.C b/gcc/testsuite/g++.dg/gomp/for-2.C new file mode 100644 index 00000000000..37e5929afa1 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/for-2.C @@ -0,0 +1,18 @@ +/* { dg-do compile } */ + +void foo() +{ + int i; + + #pragma omp for nowait + for (i = 0; i < 10; ++i) ; + + #pragma omp for nowait nowait /* { dg-error "too many" } */ + for (i = 0; i < 10; ++i) ; + + #pragma omp for ordered + for (i = 0; i < 10; ++i) ; + + #pragma omp for ordered ordered /* { dg-error "too many" } */ + for (i = 0; i < 10; ++i) ; +} diff --git a/gcc/testsuite/g++.dg/gomp/for-3.C b/gcc/testsuite/g++.dg/gomp/for-3.C new file mode 100644 index 00000000000..fcf5a2c1b23 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/for-3.C @@ -0,0 +1,62 @@ +// { dg-do compile } + +int bar (); + +void foo() +{ + int i; + + #pragma omp for schedule // { dg-error "expected" } + for (i = 0; i < 10; ++i) ; + + #pragma omp for schedule static // { dg-error "expected" } + for (i = 0; i < 10; ++i) ; + + #pragma omp for schedule ( // { dg-error "invalid schedule kind" } + for (i = 0; i < 10; ++i) ; + + #pragma omp for schedule ( static // { dg-error "expected" } + for (i = 0; i < 10; ++i) ; + + #pragma omp for schedule ( static ) + for (i = 0; i < 10; ++i) ; + + #pragma omp for schedule ( foo ) // { dg-error "invalid schedule kind" } + for (i = 0; i < 10; ++i) ; + + #pragma omp for schedule ( static 1 // { dg-error "expected" } + for (i = 0; i < 10; ++i) ; + + #pragma omp for schedule ( static 1 ) nowait // { dg-error "expected" } + for (i = 0; i < 10; ++i) ; + + #pragma omp for schedule ( static, 1 ) nowait + for (i = 0; i < 10; ++i) ; + + #pragma omp for schedule ( static, 1, 1 ) nowait // { dg-error "expected" } + for (i = 0; i < 10; ++i) ; + + #pragma omp for schedule ( static, 1 + 1 ) nowait + for (i = 0; i < 10; ++i) ; + + #pragma omp for schedule ( static, 1.0 ) // { dg-error "integral" } + for (i = 0; i < 10; ++i) ; + + #pragma omp for schedule (dynamic) + for (i = 0; i < 10; ++i) ; + + #pragma omp for schedule (dynamic, bar ()) + for (i = 0; i < 10; ++i) ; + + #pragma omp for schedule (guided) + for (i = 0; i < 10; ++i) ; + + #pragma omp for schedule (guided, bar ()) + for (i = 0; i < 10; ++i) ; + + #pragma omp for schedule (runtime) + for (i = 0; i < 10; ++i) ; + + #pragma omp for schedule (runtime, bar ()) // { dg-error "does not take" } + for (i = 0; i < 10; ++i) ; +} diff --git a/gcc/testsuite/g++.dg/gomp/for-4.C b/gcc/testsuite/g++.dg/gomp/for-4.C new file mode 100644 index 00000000000..fb6994ea20b --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/for-4.C @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-ompexp" } */ + +extern void bar(int); + +void foo (int n) +{ + int i; + + #pragma omp for schedule(dynamic) + for (i = 0; i < n; ++i) + bar(i); +} + +/* { dg-final { scan-tree-dump-times "GOMP_loop_dynamic_start" 1 "ompexp" } } */ +/* { dg-final { scan-tree-dump-times "GOMP_loop_dynamic_next" 1 "ompexp" } } */ +/* { dg-final { cleanup-tree-dump "ompexp" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/for-5.C b/gcc/testsuite/g++.dg/gomp/for-5.C new file mode 100644 index 00000000000..5912a4e5561 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/for-5.C @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-ompexp" } */ + +extern void bar(int); + +void foo (int n) +{ + int i; + + #pragma omp for schedule(guided) + for (i = 0; i < n; ++i) + bar(i); +} + +/* { dg-final { scan-tree-dump-times "GOMP_loop_guided_start" 1 "ompexp" } } */ +/* { dg-final { scan-tree-dump-times "GOMP_loop_guided_next" 1 "ompexp" } } */ +/* { dg-final { cleanup-tree-dump "ompexp" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/for-6.C b/gcc/testsuite/g++.dg/gomp/for-6.C new file mode 100644 index 00000000000..100ee2c8c21 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/for-6.C @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-ompexp" } */ + +extern void bar(int); + +void foo (int n) +{ + int i; + + #pragma omp for schedule(runtime) + for (i = 0; i < n; ++i) + bar(i); +} + +/* { dg-final { scan-tree-dump-times "GOMP_loop_runtime_start" 1 "ompexp" } } */ +/* { dg-final { scan-tree-dump-times "GOMP_loop_runtime_next" 1 "ompexp" } } */ +/* { dg-final { cleanup-tree-dump "ompexp" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/for-7.C b/gcc/testsuite/g++.dg/gomp/for-7.C new file mode 100644 index 00000000000..10763dc596c --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/for-7.C @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-ompexp" } */ + +extern void bar(int); + +void foo (int n) +{ + int i; + + #pragma omp for schedule(static) ordered + for (i = 0; i < n; ++i) + bar(i); +} + +/* { dg-final { scan-tree-dump-times "GOMP_loop_ordered_static_start" 1 "ompexp" } } */ +/* { dg-final { scan-tree-dump-times "GOMP_loop_ordered_static_next" 1 "ompexp" } } */ +/* { dg-final { cleanup-tree-dump "ompexp" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/for-8.C b/gcc/testsuite/g++.dg/gomp/for-8.C new file mode 100644 index 00000000000..1bc66c49a0d --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/for-8.C @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-ompexp" } */ + +extern void bar(int); + +void foo (int n) +{ + int i; + + #pragma omp for schedule(dynamic) ordered + for (i = 0; i < n; ++i) + bar(i); +} + +/* { dg-final { scan-tree-dump-times "GOMP_loop_ordered_dynamic_start" 1 "ompexp" } } */ +/* { dg-final { scan-tree-dump-times "GOMP_loop_ordered_dynamic_next" 1 "ompexp" } } */ +/* { dg-final { cleanup-tree-dump "ompexp" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/for-9.C b/gcc/testsuite/g++.dg/gomp/for-9.C new file mode 100644 index 00000000000..af99e216e79 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/for-9.C @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-ompexp" } */ + +extern void bar(int); + +void foo (int n) +{ + int i; + + #pragma omp for schedule(guided) ordered + for (i = 0; i < n; ++i) + bar(i); +} + +/* { dg-final { scan-tree-dump-times "GOMP_loop_ordered_guided_start" 1 "ompexp" } } */ +/* { dg-final { scan-tree-dump-times "GOMP_loop_ordered_guided_next" 1 "ompexp" } } */ +/* { dg-final { cleanup-tree-dump "ompexp" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/gomp.exp b/gcc/testsuite/g++.dg/gomp/gomp.exp new file mode 100644 index 00000000000..851c1c9bf4f --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/gomp.exp @@ -0,0 +1,11 @@ +# Load support procs. +load_lib g++-dg.exp + +# Initialize `dg'. +dg-init + +# Main loop. +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C]] "" "-fopenmp" + +# All done. +dg-finish diff --git a/gcc/testsuite/g++.dg/gomp/macro-1.C b/gcc/testsuite/g++.dg/gomp/macro-1.C new file mode 100644 index 00000000000..b04610d2ccf --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/macro-1.C @@ -0,0 +1,10 @@ +// { dg-do compile } + +#define N 10 + +extern void bar(void); +void foo(void) +{ + #pragma omp parallel num_threads(N) + bar(); +} diff --git a/gcc/testsuite/g++.dg/gomp/macro-2.C b/gcc/testsuite/g++.dg/gomp/macro-2.C new file mode 100644 index 00000000000..75d6490cd7c --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/macro-2.C @@ -0,0 +1,14 @@ +// { dg-do compile } + +#define p parallel +#define s(x) shared(x##1, x##2) +#define d(x) default(x) + +void bar(int, int, int, int); +void foo(void) +{ + int a1, a2, b1, b2; + + #pragma omp p s(a) s(b) d(none) + bar(a1, a2, b1, b2); +} diff --git a/gcc/testsuite/g++.dg/gomp/master-1.C b/gcc/testsuite/g++.dg/gomp/master-1.C new file mode 100644 index 00000000000..2681c216a3f --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/master-1.C @@ -0,0 +1,22 @@ +/* { dg-do compile } */ + +extern void bar(int); + +void foo (void) +{ + #pragma omp master + bar(0); + + #pragma omp master + { + bar(1); + bar(2); + } + + /* Yes, this is legal -- structured-block contains statement contains + openmp-construct contains master-construct. */ + #pragma omp master + #pragma omp master + #pragma omp master + ; +} diff --git a/gcc/testsuite/g++.dg/gomp/master-2.C b/gcc/testsuite/g++.dg/gomp/master-2.C new file mode 100644 index 00000000000..05320662724 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/master-2.C @@ -0,0 +1,7 @@ +/* { dg-do compile } */ + +void f1(void) +{ + #pragma omp master asdf /* { dg-error "expected" } */ + #pragma omp master +} /* { dg-error "expected" } */ diff --git a/gcc/testsuite/g++.dg/gomp/master-3.C b/gcc/testsuite/g++.dg/gomp/master-3.C new file mode 100644 index 00000000000..37966106df5 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/master-3.C @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-omplower" } */ + +extern void bar(int); + +void foo (void) +{ + #pragma omp master + bar(0); +} + +/* { dg-final { scan-tree-dump-times "omp_get_thread_num" 1 "omplower" } } */ +/* { dg-final { cleanup-tree-dump "omplower" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/method-1.C b/gcc/testsuite/g++.dg/gomp/method-1.C new file mode 100644 index 00000000000..3d8235656b1 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/method-1.C @@ -0,0 +1,18 @@ +/* PR c++/24513 */ +/* { dg-do compile } */ + +struct S +{ + void foo (int *p) + { +#pragma omp parallel for + for (int i = 0; i < 1000; ++i) + p[i]=0; + } + void bar () + { +#pragma omp master + j = 2; + } + int j; +}; diff --git a/gcc/testsuite/g++.dg/gomp/ordered-1.C b/gcc/testsuite/g++.dg/gomp/ordered-1.C new file mode 100644 index 00000000000..a1cd7f48602 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/ordered-1.C @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-omplower" } */ + +extern void bar(int); + +void foo (void) +{ + #pragma omp ordered + bar(0); + + #pragma omp ordered + { + bar(1); + bar(2); + } +} + +/* { dg-final { scan-tree-dump-times "GOMP_ordered_start" 2 "omplower" } } */ +/* { dg-final { scan-tree-dump-times "GOMP_ordered_end" 2 "omplower" } } */ +/* { dg-final { cleanup-tree-dump "omplower" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/ordered-2.C b/gcc/testsuite/g++.dg/gomp/ordered-2.C new file mode 100644 index 00000000000..6c2b4329c64 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/ordered-2.C @@ -0,0 +1,7 @@ +/* { dg-do compile } */ + +void f1(void) +{ + #pragma omp ordered asdf /* { dg-error "expected" } */ + #pragma omp ordered +} /* { dg-error "expected" } */ diff --git a/gcc/testsuite/g++.dg/gomp/parallel-1.C b/gcc/testsuite/g++.dg/gomp/parallel-1.C new file mode 100644 index 00000000000..c5c233b76eb --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/parallel-1.C @@ -0,0 +1,17 @@ +// { dg-do compile } + +void foo() +{ + int i; + + #pragma omp parallel + { + #pragma omp parallel + { + #pragma omp parallel + { + i++; + } + } + } +} diff --git a/gcc/testsuite/g++.dg/gomp/parallel-2.C b/gcc/testsuite/g++.dg/gomp/parallel-2.C new file mode 100644 index 00000000000..68e577766b1 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/parallel-2.C @@ -0,0 +1,17 @@ +// { dg-do compile } + +void foo() +{ + int i; + + #pragma omp parallel default(none) // { dg-error "enclosing" } + { + #pragma omp parallel + { + #pragma omp parallel default(none) // { dg-error "enclosing" } + { + i++; // { dg-error "not specified" } + } + } + } +} diff --git a/gcc/testsuite/g++.dg/gomp/parallel-3.C b/gcc/testsuite/g++.dg/gomp/parallel-3.C new file mode 100644 index 00000000000..633d7ba5998 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/parallel-3.C @@ -0,0 +1,15 @@ +// { dg-do compile } + +extern int printf (const char *, ...); + +int main (void) +{ + double d = 6; + int i = 1; +#pragma omp parallel shared(d) private(i) num_threads (4 + i) + { + i = 4; + printf ("%s %d %g\n", "Hello, World!", i, d); + } + return 0; +} diff --git a/gcc/testsuite/g++.dg/gomp/parallel-4.C b/gcc/testsuite/g++.dg/gomp/parallel-4.C new file mode 100644 index 00000000000..ca06aeef9ef --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/parallel-4.C @@ -0,0 +1,24 @@ +/* { dg-do compile } */ + +extern int foo(void); +extern void bar(void); + +int main () +{ + /* Malformed uses of 'if' and 'num_threads'. */ + #pragma omp parallel if (foo () > 10) if (foo () == 3) /* { dg-error "too many" } */ + { + bar (); + } + + #pragma omp parallel num_threads (3) num_threads (20) /* { dg-error "too many" } */ + { + bar (); + } + + /* Valid uses of 'if' and 'num_threads'. */ + #pragma omp parallel if (foo () == 10) num_threads (foo ()) + { + bar (); + } +} diff --git a/gcc/testsuite/g++.dg/gomp/parallel-5.C b/gcc/testsuite/g++.dg/gomp/parallel-5.C new file mode 100644 index 00000000000..b8cd174a31b --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/parallel-5.C @@ -0,0 +1,11 @@ +// { dg-do compile } + +extern void bar (void); + +int main (void) +{ + int i; +#pragma omp parallel for nowait /* { dg-error "'nowait'" } */ + for (i = 0; i < 10; i++) + bar (); +} diff --git a/gcc/testsuite/g++.dg/gomp/pr24849.C b/gcc/testsuite/g++.dg/gomp/pr24849.C new file mode 100644 index 00000000000..f3564371992 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/pr24849.C @@ -0,0 +1,19 @@ +/* { dg-do compile } */ + +template struct Healpix_Map { + T *map; + int npix_; + + void Import_nograde (const Healpix_Map &orig) { +#pragma omp parallel +{ + int m; +#pragma omp for schedule (dynamic) + for (m=0; m &a, Healpix_Map &b) { + a.Import_nograde(b); + } diff --git a/gcc/testsuite/g++.dg/gomp/pr25874.C b/gcc/testsuite/g++.dg/gomp/pr25874.C new file mode 100644 index 00000000000..02adef97f56 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/pr25874.C @@ -0,0 +1,23 @@ +int foo(); + +struct wigner_d + { + void recurse () { + int dd; + for (int j=0; j<=1; ++j) { +#pragma omp parallel + dd=5; + } + } + }; + +template void rotate_alm(T arg) + { + wigner_d rec; + rec.recurse(); +#pragma omp parallel + foo(); + } + +template void rotate_alm(float arg); +template void rotate_alm(double arg); diff --git a/gcc/testsuite/g++.dg/gomp/sections-1.C b/gcc/testsuite/g++.dg/gomp/sections-1.C new file mode 100644 index 00000000000..43704908e43 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/sections-1.C @@ -0,0 +1,39 @@ +/* { dg-do compile } */ + +extern void bar(int); + +void f1(void) +{ + #pragma omp sections nowait + { + bar (1); + #pragma omp section + bar (2); + #pragma omp section + bar (3); + #pragma omp section + bar (4); + #pragma omp section + bar (5); + } +} + +void f2(void) +{ + #pragma omp sections + { + #pragma omp section + { + bar (1); + bar (1); + } + #pragma omp section + bar (2); + #pragma omp section + bar (3); + #pragma omp section + bar (4); + #pragma omp section + bar (5); + } +} diff --git a/gcc/testsuite/g++.dg/gomp/sections-2.C b/gcc/testsuite/g++.dg/gomp/sections-2.C new file mode 100644 index 00000000000..aabdfaf8069 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/sections-2.C @@ -0,0 +1,29 @@ +/* { dg-do compile } */ + +extern void bar(int); +void foo(void) +{ + #pragma omp sections + bar (0); // { dg-error "expected" } + + #pragma omp sections + { + } // { dg-error "expected" } + + #pragma omp sections + { + bar (1); + } + + #pragma omp sections + { + #pragma omp section + bar(2); + bar(3); // { dg-error "expected" } + bar(4); + #pragma omp section + bar(5); + bar(6); // { dg-error "expected" } + bar(7); + } +} diff --git a/gcc/testsuite/g++.dg/gomp/sections-3.C b/gcc/testsuite/g++.dg/gomp/sections-3.C new file mode 100644 index 00000000000..d8fb2a09d30 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/sections-3.C @@ -0,0 +1,15 @@ + +// { dg-do compile } + +extern void bar (void); + +int main (void) +{ + #pragma omp parallel sections nowait /* { dg-error "'nowait'" } */ + { + #pragma omp section + { bar(); } + #pragma omp section + { bar(); } + } +} diff --git a/gcc/testsuite/g++.dg/gomp/sections-4.C b/gcc/testsuite/g++.dg/gomp/sections-4.C new file mode 100644 index 00000000000..44e7de98c20 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/sections-4.C @@ -0,0 +1,13 @@ +/* PR c++/24613 */ +/* { dg-compile } */ + +#pragma omp section /* { dg-error "may only be used in" } */ + +int i; + +void +foo (void) +{ + #pragma omp section /* { dg-error "may only be used in" } */ + i++; +} diff --git a/gcc/testsuite/g++.dg/gomp/sharing-1.C b/gcc/testsuite/g++.dg/gomp/sharing-1.C new file mode 100644 index 00000000000..83b81809834 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/sharing-1.C @@ -0,0 +1,77 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target tls } */ + +int thrglobalvar; +#pragma omp threadprivate (thrglobalvar) +int globalvar; +const struct S +{ + int x; +} constvar = { 8 }; +struct T +{ + static T t; + int i; +}; +T T::t = { 6 }; +/* const qualified type, but mutable member -> not predetermined. */ +const struct U +{ + int x; + mutable int y; +} constmutvar = { 6, 4 }; + +int +foo (int x) +{ + return x; +} + +int +bar (int *x) +{ + return *x; +} + +int +baz (U u) +{ + return u.x; +} + +int +main (void) +{ + static int thrlocvar; +#pragma omp threadprivate (thrlocvar) + static int locvar; + static int *p; + int i, j, s, l; + + p = new int; + *p = 7; + s = 6; + l = 0; +#pragma omp parallel for /* { dg-error "enclosing parallel" } */ \ + default (none) private (p) shared (s) + for (i = 0; i < 64; i++) + { + int k = foo (0); /* Predetermined - private (automatic var declared */ + k++; /* in scope of construct). */ + thrglobalvar++; /* Predetermined - threadprivate. */ + thrlocvar++; /* Predetermined - threadprivate. */ + foo (i); /* Predetermined - private (omp for loop variable). */ + foo (constvar.x); /* Predetermined - shared (const qualified type). */ + foo (T::t.i); /* Predetermined - shared (static data member). */ + foo (*p); /* *p predetermined - shared (heap allocated */ + (*p)++; /* storage). */ + bar (p); /* Explicitly determined - private. */ + foo (s); /* Explicitly determined - shared. */ + globalvar++; /* { dg-error "not specified in" } */ + locvar++; /* { dg-error "not specified in" } */ + l++; /* { dg-error "not specified in" } */ + for (j = 0; j < 2; j++); /* { dg-error "not specified in" } */ + baz (constmutvar);/* { dg-error "not specified in" } */ + } + return 0; +} diff --git a/gcc/testsuite/g++.dg/gomp/tls-1.C b/gcc/testsuite/g++.dg/gomp/tls-1.C new file mode 100644 index 00000000000..bfe62cb009b --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/tls-1.C @@ -0,0 +1,18 @@ +// { dg-do compile } +// { dg-require-effective-target tls } + +int tp1; +static int tp2; +extern int tp3; + +int tp4 = 1; +static int tp5 = 1; + +#pragma omp threadprivate (tp1, tp2, tp3, tp4, tp5) + +#pragma omp threadprivate (undef) // { dg-error "declared" } + +int tp6; +int foo(void) { return tp6; } + +#pragma omp threadprivate (tp6) // { dg-error "after first use" } diff --git a/gcc/testsuite/g++.dg/gomp/tls-2.C b/gcc/testsuite/g++.dg/gomp/tls-2.C new file mode 100644 index 00000000000..80275f9081c --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/tls-2.C @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target tls } */ + +extern char buf[]; +#pragma omp threadprivate (buf) /* { dg-error "has incomplete type" } */ + +void +foo (void) +{ + int i; +#pragma omp threadprivate (i) /* { dg-error "automatic variable" } */ + i = 0; +} diff --git a/gcc/testsuite/g++.dg/gomp/tls-3.C b/gcc/testsuite/g++.dg/gomp/tls-3.C new file mode 100644 index 00000000000..c42d74c4d57 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/tls-3.C @@ -0,0 +1,25 @@ +// { dg-do compile } +// { dg-require-effective-target tls } + +#define thr threadprivate + +int i; +#pragma omp thr (i) +namespace N +{ + int j; +#pragma omp thr (j) +}; +struct S +{ + static int s; +#pragma omp thr (s) // { dg-error "is not file, namespace or block scope" } +}; + +int +foo () +{ + static int k; +#pragma omp thr (k) + return k++ + S::s; +} diff --git a/gcc/testsuite/g++.dg/gomp/tpl-atomic-1.C b/gcc/testsuite/g++.dg/gomp/tpl-atomic-1.C new file mode 100644 index 00000000000..ff1e3632db6 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/tpl-atomic-1.C @@ -0,0 +1,26 @@ +// { dg-do compile } + +int check; + +template void foo() +{ + #pragma omp atomic + check |= sizeof(T); +} + +template void bar(T *x, T y) +{ + #pragma omp atomic + *x += y; +} + +void test () +{ + int i; + long l; + + foo(); + foo(); + bar(&i, 4); + bar(&l, 8L); +} diff --git a/gcc/testsuite/g++.dg/gomp/tpl-atomic-2.C b/gcc/testsuite/g++.dg/gomp/tpl-atomic-2.C new file mode 100644 index 00000000000..363bd103d8e --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/tpl-atomic-2.C @@ -0,0 +1,41 @@ +// { dg-do compile } + +struct S { int x; } s; + +// Make sure we detect errors on non-type-dependent things +// even when the templates are never instantiated. +template void f1() +{ + #pragma omp atomic + s += 1; // { dg-error "invalid" } +} + +template void f2(float *f) +{ + #pragma omp atomic + *f |= 1; // { dg-error "invalid|evaluation" } +} + +// Here the rhs is dependent, but not type dependent. +// ??? Fails. See the comment in finish_omp_atomic. +template void f3(float *f) +{ + #pragma omp atomic + *f |= sizeof (T); // { dg-error "invalid|evaluation" "" { xfail *-*-* } } +} + +// And the converse, no error here because we're never fed a T. +template void f4(T *t) +{ + #pragma omp atomic + *t += 1; +} + +// Here we'll let it go, because the rhs is type dependent and +// we can't properly instantiate the statement, and we do most +// of the semantic analysis concurrent with that. +template void f5(float *f) +{ + #pragma omp atomic + *f |= (T)sizeof(T); // { dg-error "invalid|evaluation" "" { xfail *-*-* } } +} diff --git a/gcc/testsuite/g++.dg/gomp/tpl-barrier-1.C b/gcc/testsuite/g++.dg/gomp/tpl-barrier-1.C new file mode 100644 index 00000000000..60567d91028 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/tpl-barrier-1.C @@ -0,0 +1,25 @@ +// PR c++/24735 +// { dg-do compile } +// { dg-options "-fopenmp -fdump-tree-gimple" } + +template void f1 () +{ + #pragma omp barrier +} + +template void f2 (bool p) +{ + if (p) + { + #pragma omp barrier + } +} + +void f3 () +{ + f1<0> (); + f2<0> (true); +} + +// { dg-final { scan-tree-dump-times "GOMP_barrier" 2 "gimple" } } +// { dg-final { cleanup-tree-dump "gimple" } } diff --git a/gcc/testsuite/g++.dg/gomp/tpl-for-1.C b/gcc/testsuite/g++.dg/gomp/tpl-for-1.C new file mode 100644 index 00000000000..e036e644715 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/tpl-for-1.C @@ -0,0 +1,17 @@ +// { dg-do compile } + +void foo(int); +void foo(long); + +template void bar() +{ + #pragma omp for + for (T i = 0; i < 10; ++i) + foo(i); +} + +void test() +{ + bar(); + bar(); +} diff --git a/gcc/testsuite/g++.dg/gomp/tpl-for-2.C b/gcc/testsuite/g++.dg/gomp/tpl-for-2.C new file mode 100644 index 00000000000..a3bb6ccd46b --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/tpl-for-2.C @@ -0,0 +1,15 @@ +// { dg-do compile } + +void foo(int); + +template void bar() +{ + #pragma omp for + for (int i = A; i < B; i += C) + foo(i); +} + +void test() +{ + bar<0, 10, 2>(); +} diff --git a/gcc/testsuite/g++.dg/gomp/tpl-for-3.C b/gcc/testsuite/g++.dg/gomp/tpl-for-3.C new file mode 100644 index 00000000000..0cafd9628b5 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/tpl-for-3.C @@ -0,0 +1,28 @@ +// { dg-do compile } + +void foo(int); + +template void bar() +{ + #pragma omp parallel for + for (typename T::T i = 0; i < T::N; ++i) + foo(i); +} + +struct A +{ + typedef int T; + static T N; +}; + +struct B +{ + typedef long T; + static T N; +}; + +void test() +{ + bar(); + bar(); +} diff --git a/gcc/testsuite/g++.dg/gomp/tpl-master-1.C b/gcc/testsuite/g++.dg/gomp/tpl-master-1.C new file mode 100644 index 00000000000..cf22e1c3fd3 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/tpl-master-1.C @@ -0,0 +1,30 @@ +// PR c++/24734 +// { dg-do compile } +// { dg-options "-fopenmp -fdump-tree-gimple" } + +int i; + +template void f1 () +{ + #pragma omp ordered + i++; +} + +template void f2 (bool p) +{ + if (p) + { + #pragma omp master + i++; + } +} + +void f3 () +{ + f1<0> (); + f2<0> (true); +} + +// { dg-final { scan-tree-dump-times "#pragma omp ordered" 1 "gimple" } } +// { dg-final { scan-tree-dump-times "#pragma omp master" 1 "gimple" } } +// { dg-final { cleanup-tree-dump "gimple" } } diff --git a/gcc/testsuite/g++.dg/gomp/tpl-parallel-1.C b/gcc/testsuite/g++.dg/gomp/tpl-parallel-1.C new file mode 100644 index 00000000000..886d07e215b --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/tpl-parallel-1.C @@ -0,0 +1,24 @@ +// { dg-do compile } + +int check; + +template void foo() +{ + check |= sizeof(T); +} + +template +void bar(void) +{ + #pragma omp parallel if (0) + foo(); +} + +int main() +{ + bar(); + bar(); + if (check != (sizeof(char) | sizeof(short))) + __builtin_trap (); + return 0; +} diff --git a/gcc/testsuite/g++.dg/gomp/tpl-parallel-2.C b/gcc/testsuite/g++.dg/gomp/tpl-parallel-2.C new file mode 100644 index 00000000000..3f2e3bb6211 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/tpl-parallel-2.C @@ -0,0 +1,20 @@ +// { dg-do compile } + +template +struct S +{ + T n; + void test(); + void work(); +}; + +template +void S::test() +{ + #pragma omp parallel num_threads(n) // { dg-error "must be integral" } + work(); +} + +template struct S; +template struct S; +template struct S; // { dg-error "instantiated from here" } diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 1c689e2037c..b7f147ce77f 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -4736,6 +4736,8 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb, if (uid >= dest_cfun->last_label_uid) dest_cfun->last_label_uid = uid + 1; } + + remove_stmt_from_eh_region (stmt); } } diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog index fd1a2315354..278cba07e3c 100644 --- a/libgomp/ChangeLog +++ b/libgomp/ChangeLog @@ -1,3 +1,7 @@ +2006-03-09 Diego Novillo + + * testsuite/libgomp.c++: New directory. + 2006-02-25 Shantonu Sen * config/posix/sem.h: Define BROKEN_POSIX_SEMAPHORES functions. diff --git a/libgomp/testsuite/libgomp.c++/c++.exp b/libgomp/testsuite/libgomp.c++/c++.exp new file mode 100644 index 00000000000..ecb4aa9a9c7 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/c++.exp @@ -0,0 +1,20 @@ +set lang_library_path "../libstdc++-v3/src/.libs" +set lang_test_file "${lang_library_path}/libstdc++.a" +set lang_link_flags "-lstdc++" + +load_lib libgomp-dg.exp + +# Initialize dg. +dg-init + +if [file exists "${blddir}/${lang_test_file}"] { + + # Gather a list of all tests. + set tests [lsort [glob -nocomplain $srcdir/$subdir/*.C]] + + # Main loop. + gfortran-dg-runtest $tests "" +} + +# All done. +dg-finish diff --git a/libgomp/testsuite/libgomp.c++/copyin-1.C b/libgomp/testsuite/libgomp.c++/copyin-1.C new file mode 100644 index 00000000000..bc12be2d2f9 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/copyin-1.C @@ -0,0 +1,34 @@ +// { dg-do run } +// { dg-require-effective-target tls_runtime } + +#include + +extern "C" void abort (void); + +int thr = 32; +#pragma omp threadprivate (thr) + +int +main (void) +{ + int l = 0; + + omp_set_dynamic (0); + omp_set_num_threads (6); + +#pragma omp parallel copyin (thr) reduction (||:l) + { + l = thr != 32; + thr = omp_get_thread_num () + 11; + } + + if (l || thr != 11) + abort (); + +#pragma omp parallel reduction (||:l) + l = thr != omp_get_thread_num () + 11; + + if (l) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/copyin-2.C b/libgomp/testsuite/libgomp.c++/copyin-2.C new file mode 100644 index 00000000000..024f5998054 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/copyin-2.C @@ -0,0 +1,34 @@ +// { dg-do run } +// { dg-require-effective-target tls_runtime } + +#include + +extern "C" void abort (void); + +struct S { int t; char buf[64]; } thr = { 32, "" }; +#pragma omp threadprivate (thr) + +int +main (void) +{ + int l = 0; + + omp_set_dynamic (0); + omp_set_num_threads (6); + +#pragma omp parallel copyin (thr) reduction (||:l) + { + l = thr.t != 32; + thr.t = omp_get_thread_num () + 11; + } + + if (l || thr.t != 11) + abort (); + +#pragma omp parallel reduction (||:l) + l = thr.t != omp_get_thread_num () + 11; + + if (l) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/ctor-1.C b/libgomp/testsuite/libgomp.c++/ctor-1.C new file mode 100644 index 00000000000..2ad3b3a6efc --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/ctor-1.C @@ -0,0 +1,65 @@ +// { dg-do run } + +#include +#include + +struct B +{ + static int icount; + static int dcount; + static int xcount; + + B(); + B(const B &); + ~B(); + B& operator=(const B &); + void doit(); +}; + +int B::icount; +int B::dcount; +int B::xcount; + +B::B() +{ + #pragma omp atomic + icount++; +} + +B::~B() +{ + #pragma omp atomic + dcount++; +} + +void B::doit() +{ + #pragma omp atomic + xcount++; +} + +static int nthreads; + +void foo() +{ + B b; + #pragma omp parallel private(b) + { + #pragma omp master + nthreads = omp_get_num_threads (); + b.doit(); + } +} + +int main() +{ + omp_set_dynamic (0); + omp_set_num_threads (4); + foo(); + + assert (B::xcount == nthreads); + assert (B::icount == nthreads+1); + assert (B::dcount == nthreads+1); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/ctor-2.C b/libgomp/testsuite/libgomp.c++/ctor-2.C new file mode 100644 index 00000000000..6611c592fda --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/ctor-2.C @@ -0,0 +1,76 @@ +// { dg-do run } + +#include +#include + +struct B +{ + static int ccount; + static int dcount; + static int xcount; + static B *expected; + + B(); + B(int); + B(const B &); + ~B(); + B& operator=(const B &); + void doit(); +}; + +int B::ccount; +int B::dcount; +int B::xcount; +B * B::expected; + +B::B(int) +{ + expected = this; +} + +B::B(const B &b) +{ + #pragma omp atomic + ccount++; + assert (&b == expected); +} + +B::~B() +{ + #pragma omp atomic + dcount++; +} + +void B::doit() +{ + #pragma omp atomic + xcount++; + assert (this != expected); +} + +static int nthreads; + +void foo() +{ + B b(0); + + #pragma omp parallel firstprivate(b) + { + #pragma omp master + nthreads = omp_get_num_threads (); + b.doit(); + } +} + +int main() +{ + omp_set_dynamic (0); + omp_set_num_threads (4); + foo(); + + assert (B::xcount == nthreads); + assert (B::ccount == nthreads); + assert (B::dcount == nthreads+1); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/ctor-3.C b/libgomp/testsuite/libgomp.c++/ctor-3.C new file mode 100644 index 00000000000..e65e4ea521b --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/ctor-3.C @@ -0,0 +1,89 @@ +// { dg-do run } + +#include +#include + +struct B +{ + static int icount; + static int dcount; + static int ccount; + static B *e_inner; + static B *e_outer; + + B(); + B(int); + B(const B &); + ~B(); + B& operator=(const B &); + void doit(); +}; + +int B::icount; +int B::dcount; +int B::ccount; +B * B::e_inner; +B * B::e_outer; + +B::B() +{ + #pragma omp atomic + icount++; +} + +B::B(int) +{ + e_outer = this; +} + +B::~B() +{ + #pragma omp atomic + dcount++; +} + +B& B::operator= (const B &b) +{ + assert (&b == e_inner); + assert (this == e_outer); + #pragma omp atomic + ccount++; + return *this; +} + +void B::doit() +{ + #pragma omp critical + { + assert (e_inner == 0); + e_inner = this; + } +} + +static int nthreads; + +void foo() +{ + B b(0); + + #pragma omp parallel sections lastprivate(b) + { + #pragma omp section + nthreads = omp_get_num_threads (); + #pragma omp section + b.doit (); + } +} + +int main() +{ + omp_set_dynamic (0); + omp_set_num_threads (4); + foo(); + + assert (B::ccount == 1); + assert (B::icount == nthreads); + assert (B::dcount == nthreads+1); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/ctor-4.C b/libgomp/testsuite/libgomp.c++/ctor-4.C new file mode 100644 index 00000000000..e4f8f82db34 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/ctor-4.C @@ -0,0 +1,90 @@ +// { dg-do run } + +#include +#include + +struct B +{ + static int ccount; + static int dcount; + static int ecount; + static B *e_inner; + static B *e_outer; + + B(); + B(int); + B(const B &); + ~B(); + B& operator=(const B &); + void doit(); +}; + +int B::ccount; +int B::dcount; +int B::ecount; +B * B::e_inner; +B * B::e_outer; + +B::B(int) +{ + e_outer = this; +} + +B::B(const B &b) +{ + assert (&b == e_outer); + #pragma omp atomic + ccount++; +} + +B::~B() +{ + #pragma omp atomic + dcount++; +} + +B& B::operator= (const B &b) +{ + assert (&b == e_inner); + assert (this == e_outer); + #pragma omp atomic + ecount++; + return *this; +} + +void B::doit() +{ + #pragma omp critical + { + assert (e_inner == 0); + e_inner = this; + } +} + +static int nthreads; + +void foo() +{ + B b(0); + + #pragma omp parallel sections firstprivate(b) lastprivate(b) + { + #pragma omp section + nthreads = omp_get_num_threads (); + #pragma omp section + b.doit (); + } +} + +int main() +{ + omp_set_dynamic (0); + omp_set_num_threads (4); + foo(); + + assert (B::ecount == 1); + assert (B::ccount == nthreads); + assert (B::dcount == nthreads+1); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/ctor-5.C b/libgomp/testsuite/libgomp.c++/ctor-5.C new file mode 100644 index 00000000000..d99a1d4628f --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/ctor-5.C @@ -0,0 +1,52 @@ +// { dg-do run } +// { dg-require-effective-target tls_runtime } + +#include +#include + +struct B +{ + static int count; + static B *expected; + + B& operator=(const B &); +}; + +int B::count; +B * B::expected; + +static B thr; +#pragma omp threadprivate(thr) + +B& B::operator= (const B &b) +{ + assert (&b == expected); + assert (this != expected); + #pragma omp atomic + count++; + return *this; +} + +static int nthreads; + +void foo() +{ + B::expected = &thr; + + #pragma omp parallel copyin(thr) + { + #pragma omp master + nthreads = omp_get_num_threads (); + } +} + +int main() +{ + omp_set_dynamic (0); + omp_set_num_threads (4); + foo(); + + assert (B::count == nthreads-1); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/ctor-6.C b/libgomp/testsuite/libgomp.c++/ctor-6.C new file mode 100644 index 00000000000..eab74e08922 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/ctor-6.C @@ -0,0 +1,50 @@ +// { dg-do run } + +#include +#include + +struct B +{ + static int count; + static B *expected; + + B& operator=(const B &); +}; + +int B::count; +B * B::expected; + +B& B::operator= (const B &b) +{ + assert (&b == expected); + assert (this != expected); + #pragma omp atomic + count++; + return *this; +} + +static int nthreads; + +void foo() +{ + #pragma omp parallel + { + B b; + #pragma omp single copyprivate(b) + { + nthreads = omp_get_num_threads (); + B::expected = &b; + } + } +} + +int main() +{ + omp_set_dynamic (0); + omp_set_num_threads (4); + foo(); + + assert (B::count == nthreads-1); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/ctor-7.C b/libgomp/testsuite/libgomp.c++/ctor-7.C new file mode 100644 index 00000000000..3d669a70791 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/ctor-7.C @@ -0,0 +1,67 @@ +// { dg-do run } + +#include +#include + +#define N 10 + +struct B +{ + static int icount; + static int dcount; + static int xcount; + + B(); + B(const B &); + ~B(); + B& operator=(const B &); + void doit(); +}; + +int B::icount; +int B::dcount; +int B::xcount; + +B::B() +{ + #pragma omp atomic + icount++; +} + +B::~B() +{ + #pragma omp atomic + dcount++; +} + +void B::doit() +{ + #pragma omp atomic + xcount++; +} + +static int nthreads; + +void foo() +{ + B b[N]; + #pragma omp parallel private(b) + { + #pragma omp master + nthreads = omp_get_num_threads (); + b[0].doit(); + } +} + +int main() +{ + omp_set_dynamic (0); + omp_set_num_threads (4); + foo(); + + assert (B::xcount == nthreads); + assert (B::icount == (nthreads+1)*N); + assert (B::dcount == (nthreads+1)*N); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/ctor-8.C b/libgomp/testsuite/libgomp.c++/ctor-8.C new file mode 100644 index 00000000000..5c0d81b73d1 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/ctor-8.C @@ -0,0 +1,77 @@ +// { dg-do run } +// { dg-require-effective-target tls_runtime } + +#include +#include + +#define N 10 +#define THR 4 + +struct B +{ + B(); + B(const B &); + ~B(); + B& operator=(const B &); + void doit(); +}; + +static B *base; +static B *threadbase; +static unsigned cmask[THR]; +static unsigned dmask[THR]; + +#pragma omp threadprivate(threadbase) + +B::B() +{ + assert (base == 0); +} + +B::B(const B &b) +{ + unsigned index = &b - base; + assert (index < N); + cmask[omp_get_thread_num()] |= 1u << index; +} + +B::~B() +{ + if (threadbase) + { + unsigned index = this - threadbase; + assert (index < N); + dmask[omp_get_thread_num()] |= 1u << index; + } +} + +void foo() +{ + B b[N]; + + base = b; + + #pragma omp parallel firstprivate(b) + { + assert (omp_get_num_threads () == THR); + threadbase = b; + } + + threadbase = 0; +} + +int main() +{ + omp_set_dynamic (0); + omp_set_num_threads (THR); + foo(); + + for (int i = 0; i < THR; ++i) + { + unsigned xmask = (1u << N) - 1; + assert (cmask[i] == xmask); + assert (dmask[i] == xmask); + } + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/ctor-9.C b/libgomp/testsuite/libgomp.c++/ctor-9.C new file mode 100644 index 00000000000..215a901f8d3 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/ctor-9.C @@ -0,0 +1,60 @@ +// { dg-do run } +// { dg-require-effective-target tls_runtime } + +#include +#include + +#define N 10 +#define THR 4 + +struct B +{ + B& operator=(const B &); +}; + +static B *base; +static B *threadbase; +static int singlethread; +#pragma omp threadprivate(threadbase) + +static unsigned cmask[THR]; + +B& B::operator= (const B &b) +{ + unsigned sindex = &b - base; + unsigned tindex = this - threadbase; + assert(sindex < N); + assert(sindex == tindex); + cmask[omp_get_thread_num ()] |= 1u << tindex; + return *this; +} + +void foo() +{ + #pragma omp parallel + { + B b[N]; + threadbase = b; + #pragma omp single copyprivate(b) + { + assert(omp_get_num_threads () == THR); + singlethread = omp_get_thread_num (); + base = b; + } + } +} + +int main() +{ + omp_set_dynamic (0); + omp_set_num_threads (THR); + foo(); + + for (int i = 0; i < THR; ++i) + if (i == singlethread) + assert(cmask[singlethread] == 0); + else + assert(cmask[i] == (1u << N) - 1); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/loop-1.C b/libgomp/testsuite/libgomp.c++/loop-1.C new file mode 100644 index 00000000000..0e83c95832f --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/loop-1.C @@ -0,0 +1,96 @@ +#include +#include +#include +#include + +#define MAX 1000 + +void main1() +{ + int i, N1, N2, step; + int a[MAX], b[MAX]; + + N1 = rand () % 13; + N2 = rand () % (MAX - 51) + 50; + step = rand () % 7 + 1; + + printf ("N1 = %d\nN2 = %d\nstep = %d\n", N1, N2, step); + + for (i = N1; i <= N2; i += step) + a[i] = 42+ i; + + /* COUNTING UP (<). Fill in array 'b' in parallel. */ + memset (b, 0, sizeof b); +#pragma omp parallel shared(a,b,N1,N2,step) private(i) + { +#pragma omp for + for (i = N1; i < N2; i += step) + b[i] = a[i]; + } + + /* COUNTING UP (<). Check that all the cells were filled in properly. */ + for (i = N1; i < N2; i += step) + if (a[i] != b[i]) + abort (); + + printf ("for (i = %d; i < %d; i += %d) [OK]\n", N1, N2, step); + + /* COUNTING UP (<=). Fill in array 'b' in parallel. */ + memset (b, 0, sizeof b); +#pragma omp parallel shared(a,b,N1,N2,step) private(i) + { +#pragma omp for + for (i = N1; i <= N2; i += step) + b[i] = a[i]; + } + + /* COUNTING UP (<=). Check that all the cells were filled in properly. */ + for (i = N1; i <= N2; i += step) + if (a[i] != b[i]) + abort (); + + printf ("for (i = %d; i <= %d; i += %d) [OK]\n", N1, N2, step); + + /* COUNTING DOWN (>). Fill in array 'b' in parallel. */ + memset (b, 0, sizeof b); +#pragma omp parallel shared(a,b,N1,N2,step) private(i) + { +#pragma omp for + for (i = N2; i > N1; i -= step) + b[i] = a[i]; + } + + /* COUNTING DOWN (>). Check that all the cells were filled in properly. */ + for (i = N2; i > N1; i -= step) + if (a[i] != b[i]) + abort (); + + printf ("for (i = %d; i > %d; i -= %d) [OK]\n", N2, N1, step); + + /* COUNTING DOWN (>=). Fill in array 'b' in parallel. */ + memset (b, 0, sizeof b); +#pragma omp parallel shared(a,b,N1,N2,step) private(i) + { +#pragma omp for + for (i = N2; i >= N1; i -= step) + b[i] = a[i]; + } + + /* COUNTING DOWN (>=). Check that all the cells were filled in properly. */ + for (i = N2; i >= N1; i -= step) + if (a[i] != b[i]) + abort (); + + printf ("for (i = %d; i >= %d; i -= %d) [OK]\n", N2, N1, step); +} + +int +main () +{ + int i; + + srand (0); + for (i = 0; i < 10; ++i) + main1(); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/loop-2.C b/libgomp/testsuite/libgomp.c++/loop-2.C new file mode 100644 index 00000000000..ea3dc588afd --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/loop-2.C @@ -0,0 +1,32 @@ +#include + +/* Orphaned work sharing. */ + +extern "C" void abort (void); + +#define N 10 + +void parloop (int *a) +{ + int i; + +#pragma omp for + for (i = 0; i < N; i++) + a[i] = i + 3; +} + +main() +{ + int i, a[N]; + +#pragma omp parallel shared(a) + { + parloop (a); + } + + for (i = 0; i < N; i++) + if (a[i] != i + 3) + abort (); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/loop-3.C b/libgomp/testsuite/libgomp.c++/loop-3.C new file mode 100644 index 00000000000..fa50f099f3f --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/loop-3.C @@ -0,0 +1,26 @@ +extern "C" void abort (void); +int a; + +void +foo () +{ + int i; + a = 30; +#pragma omp barrier +#pragma omp for lastprivate (a) + for (i = 0; i < 1024; i++) + { + a = i; + } + if (a != 1023) + abort (); +} + +int +main (void) +{ +#pragma omp parallel num_threads (64) + foo (); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/loop-4.C b/libgomp/testsuite/libgomp.c++/loop-4.C new file mode 100644 index 00000000000..731f2345021 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/loop-4.C @@ -0,0 +1,20 @@ +extern "C" void abort (void); + +main() +{ + int i, a; + + a = 30; + +#pragma omp parallel for firstprivate (a) lastprivate (a) \ + num_threads (2) schedule(static) + for (i = 0; i < 10; i++) + a = a + i; + + /* The thread that owns the last iteration will have computed + 30 + 5 + 6 + 7 + 8 + 9 = 65. */ + if (a != 65) + abort (); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/loop-5.C b/libgomp/testsuite/libgomp.c++/loop-5.C new file mode 100644 index 00000000000..c427efa85c6 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/loop-5.C @@ -0,0 +1,19 @@ +extern "C" void abort (); + +int check; +int f1() { check |= 1; return 1; } +int f2() { check |= 2; return 11; } +int f3() { check |= 4; return 2; } + +int a[12]; + +int main() +{ + #pragma omp for + for (int i = f1(); i <= f2(); i += f3()) + a[i] = 1; + + for (int i = 0; i < 12; ++i) + if (a[i] != (i & 1)) + abort (); +} diff --git a/libgomp/testsuite/libgomp.c++/loop-6.C b/libgomp/testsuite/libgomp.c++/loop-6.C new file mode 100644 index 00000000000..fa26c6892cf --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/loop-6.C @@ -0,0 +1,24 @@ +// { dg-do run } + +extern "C" void abort (void); + +volatile int count; +static int test(void) +{ + return ++count > 0; +} + +int main() +{ + int i; + #pragma omp for + for (i = 0; i < 10; ++i) + { + if (test()) + continue; + abort (); + } + if (i != count) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/loop-7.C b/libgomp/testsuite/libgomp.c++/loop-7.C new file mode 100644 index 00000000000..4eccb7fca01 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/loop-7.C @@ -0,0 +1,22 @@ +// PR c++/24502 +// { dg-do run } + +extern "C" void abort (); + +template T +foo (T r) +{ + T i; +#pragma omp for + for (i = 0; i < 10; i++) + r += i; + return r; +} + +int +main () +{ + if (foo (0) != 10 * 9 / 2 || foo (2L) != 10L * 9 / 2 + 2) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/master-1.C b/libgomp/testsuite/libgomp.c++/master-1.C new file mode 100644 index 00000000000..734b4e2cd98 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/master-1.C @@ -0,0 +1,24 @@ +// PR c++/24734 +// { dg-do run } + +extern "C" void abort (); +int i; + +template void +foo () +{ + #pragma omp parallel + { + #pragma omp master + i++; + } +} + +int +main () +{ + foo<0> (); + if (i != 1) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/nested-1.C b/libgomp/testsuite/libgomp.c++/nested-1.C new file mode 100644 index 00000000000..8d0e397bd2e --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/nested-1.C @@ -0,0 +1,28 @@ +// { dg-do run } + +extern "C" void abort(void); +#define N 1000 + +int foo() +{ + int i = 0, j; + + #pragma omp parallel for num_threads(2) shared (i) + for (j = 0; j < N; ++j) + { + #pragma omp parallel num_threads(1) shared (i) + { + #pragma omp atomic + i++; + } + } + + return i; +} + +int main() +{ + if (foo() != N) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/parallel-1.C b/libgomp/testsuite/libgomp.c++/parallel-1.C new file mode 100644 index 00000000000..3c931471328 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/parallel-1.C @@ -0,0 +1,40 @@ +#include + +extern "C" void abort (void); + +int +foo (void) +{ + return 10; +} + +main () +{ + int A = 0; + + #pragma omp parallel if (foo () > 10) shared (A) + { + A = omp_get_num_threads (); + } + + if (A != 1) + abort (); + + #pragma omp parallel if (foo () == 10) num_threads (3) shared (A) + { + A = omp_get_num_threads (); + } + + if (A != 3) + abort (); + + #pragma omp parallel if (foo () == 10) num_threads (foo ()) shared (A) + { + A = omp_get_num_threads (); + } + + if (A != 10) + abort (); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/pr24455-1.C b/libgomp/testsuite/libgomp.c++/pr24455-1.C new file mode 100644 index 00000000000..e7f38f8ab7b --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/pr24455-1.C @@ -0,0 +1,6 @@ +// { dg-do compile } +// { dg-require-effective-target tls } +extern int i; +#pragma omp threadprivate (i) + +int i; diff --git a/libgomp/testsuite/libgomp.c++/pr24455.C b/libgomp/testsuite/libgomp.c++/pr24455.C new file mode 100644 index 00000000000..ad43b47b2c5 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/pr24455.C @@ -0,0 +1,23 @@ +// { dg-do run } +// { dg-additional-sources pr24455-1.C } +// { dg-require-effective-target tls_runtime } + +extern "C" void abort (void); + +extern int i; +#pragma omp threadprivate(i) + +int main() +{ + i = 0; + +#pragma omp parallel default(none) num_threads(10) copyin(i) + { + i++; +#pragma omp barrier + if (i != 1) + abort (); + } + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/reduction-1.C b/libgomp/testsuite/libgomp.c++/reduction-1.C new file mode 100644 index 00000000000..665163af09f --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/reduction-1.C @@ -0,0 +1,36 @@ +#include +#include + +int +main (void) +{ + int i = 0, j = 0, k = ~0; + double d = 1.0; +#pragma omp parallel num_threads(4) reduction(+:i) reduction(*:d) reduction(&:k) + { + if (i != 0 || d != 1.0 || k != ~0) +#pragma omp atomic + j |= 1; + + if (omp_get_num_threads () != 4) +#pragma omp atomic + j |= 2; + + i = omp_get_thread_num (); + d = i + 1; + k = ~(1 << (2 * i)); + } + + if (j & 1) + abort (); + if ((j & 2) == 0) + { + if (i != (0 + 1 + 2 + 3)) + abort (); + if (d != (1.0 * 2.0 * 3.0 * 4.0)) + abort (); + if (k != (~0 ^ 0x55)) + abort (); + } + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/reduction-2.C b/libgomp/testsuite/libgomp.c++/reduction-2.C new file mode 100644 index 00000000000..52b3faff787 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/reduction-2.C @@ -0,0 +1,50 @@ +#include +#include + +int +main (void) +{ + int i = 0, j = 0, k = ~0, l; + double d = 1.0; +#pragma omp parallel num_threads(4) + { +#pragma omp single + { + i = 16; + k ^= (1 << 16); + d += 32.0; + } + +#pragma omp for reduction(+:i) reduction(*:d) reduction(&:k) + for (l = 0; l < 4; l++) + { + if (omp_get_num_threads () == 4 && (i != 0 || d != 1.0 || k != ~0)) +#pragma omp atomic + j |= 1; + + if (l == omp_get_thread_num ()) + { + i = omp_get_thread_num (); + d = i + 1; + k = ~(1 << (2 * i)); + } + } + + if (omp_get_num_threads () == 4) + { + if (i != (16 + 0 + 1 + 2 + 3)) +#pragma omp atomic + j |= 2; + if (d != (33.0 * 1.0 * 2.0 * 3.0 * 4.0)) +#pragma omp atomic + j |= 4; + if (k != (~0 ^ 0x55 ^ (1 << 16))) +#pragma omp atomic + j |= 8; + } + } + + if (j) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/reduction-3.C b/libgomp/testsuite/libgomp.c++/reduction-3.C new file mode 100644 index 00000000000..4f8f2fc1236 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/reduction-3.C @@ -0,0 +1,51 @@ +#include +#include + +int +main (void) +{ + int i = 0, j = 0, k = ~0, l; + double d = 1.0; +#pragma omp parallel num_threads(4) + { +#pragma omp single + { + i = 16; + k ^= (1 << 16); + d += 32.0; + } + +#pragma omp for reduction(+:i) reduction(*:d) reduction(&:k) nowait + for (l = 0; l < 4; l++) + { + if (omp_get_num_threads () == 4 && (i != 0 || d != 1.0 || k != ~0)) +#pragma omp atomic + j |= 1; + + if (l == omp_get_thread_num ()) + { + i = omp_get_thread_num (); + d = i + 1; + k = ~(1 << (2 * i)); + } + } + + if (omp_get_num_threads () == 4) + { +#pragma omp barrier + if (i != (16 + 0 + 1 + 2 + 3)) +#pragma omp atomic + j |= 2; + if (d != (33.0 * 1.0 * 2.0 * 3.0 * 4.0)) +#pragma omp atomic + j |= 4; + if (k != (~0 ^ 0x55 ^ (1 << 16))) +#pragma omp atomic + j |= 8; + } + } + + if (j) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/sections-1.C b/libgomp/testsuite/libgomp.c++/sections-1.C new file mode 100644 index 00000000000..32c93dbdef6 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/sections-1.C @@ -0,0 +1,64 @@ +/****************************************************************************** +* FILE: omp_workshare2.c +* DESCRIPTION: +* OpenMP Example - Sections Work-sharing - C/C++ Version +* In this example, the OpenMP SECTION directive is used to assign +* different array operations to threads that execute a SECTION. Each +* thread receives its own copy of the result array to work with. +* AUTHOR: Blaise Barney 5/99 +* LAST REVISED: 04/06/05 +******************************************************************************/ +#include +#include +#include +#define N 50 + +int main (int argc, char *argv[]) { + +int i, nthreads, tid; +float a[N], b[N], c[N]; + +/* Some initializations */ +for (i=0; i + +extern "C" void abort (void); + +struct Y +{ + int l[5][10]; +}; + +struct X +{ + struct Y y; + float b[10]; +}; + +void +parallel (int a, int b) +{ + int i, j; + struct X A[10][5]; + a = b = 3; + + for (i = 0; i < 10; i++) + for (j = 0; j < 5; j++) + A[i][j].y.l[3][3] = -10; + + #pragma omp parallel shared (a, b, A) num_threads (5) + { + int i, j; + + #pragma omp atomic + a += omp_get_num_threads (); + + #pragma omp atomic + b += omp_get_num_threads (); + + #pragma omp for private (j) + for (i = 0; i < 10; i++) + for (j = 0; j < 5; j++) + A[i][j].y.l[3][3] += 20; + + } + + for (i = 0; i < 10; i++) + for (j = 0; j < 5; j++) + if (A[i][j].y.l[3][3] != 10) + abort (); + + if (a != 28) + abort (); + + if (b != 28) + abort (); +} + +main() +{ + parallel (1, 2); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/shared-2.C b/libgomp/testsuite/libgomp.c++/shared-2.C new file mode 100644 index 00000000000..01855fbd496 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/shared-2.C @@ -0,0 +1,47 @@ +extern "C" void abort (void); + +void +parallel (int a, int b) +{ + int bad, LASTPRIV, LASTPRIV_SEC; + int i; + + a = b = 3; + + bad = 0; + + #pragma omp parallel firstprivate (a,b) shared (bad) num_threads (5) + { + if (a != 3 || b != 3) + bad = 1; + + #pragma omp for lastprivate (LASTPRIV) + for (i = 0; i < 10; i++) + LASTPRIV = i; + + #pragma omp sections lastprivate (LASTPRIV_SEC) + { + #pragma omp section + { LASTPRIV_SEC = 3; } + + #pragma omp section + { LASTPRIV_SEC = 42; } + } + + } + + if (LASTPRIV != 9) + abort (); + + if (LASTPRIV_SEC != 42) + abort (); + + if (bad) + abort (); +} + +int main() +{ + parallel (1, 2); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/single-1.C b/libgomp/testsuite/libgomp.c++/single-1.C new file mode 100644 index 00000000000..e318a48ca5c --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/single-1.C @@ -0,0 +1,19 @@ +extern "C" void abort (void); + +main() +{ + int i = 0; + + #pragma omp parallel shared (i) + { + #pragma omp single + { + i++; + } + } + + if (i != 1) + abort (); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/single-2.C b/libgomp/testsuite/libgomp.c++/single-2.C new file mode 100644 index 00000000000..c2dd228568d --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/single-2.C @@ -0,0 +1,36 @@ +extern "C" void abort (void); + +struct X +{ + int a; + char b; + int c; +}; + +main() +{ + int i = 0; + struct X x; + int bad = 0; + + #pragma omp parallel private (i, x) shared (bad) + { + i = 5; + + #pragma omp single copyprivate (i, x) + { + i++; + x.a = 23; + x.b = 42; + x.c = 26; + } + + if (i != 6 || x.a != 23 || x.b != 42 || x.c != 26) + bad = 1; + } + + if (bad) + abort (); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/single-3.C b/libgomp/testsuite/libgomp.c++/single-3.C new file mode 100644 index 00000000000..abc7f44b311 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/single-3.C @@ -0,0 +1,21 @@ +extern "C" void abort (void); + +void +single (int a, int b) +{ + #pragma omp single copyprivate(a) copyprivate(b) + { + a = b = 5; + } + + if (a != b) + abort (); +} + +int main() +{ + #pragma omp parallel + single (1, 2); + + return 0; +} -- 2.11.4.GIT