diff options
author | Ian Lance Taylor <iant@golang.org> | 2021-09-13 10:37:49 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2021-09-13 10:37:49 -0700 |
commit | e252b51ccde010cbd2a146485d8045103cd99533 (patch) | |
tree | e060f101cdc32bf5e520de8e5275db9d4236b74c /gcc/c | |
parent | f10c7c4596dda99d2ee872c995ae4aeda65adbdf (diff) | |
parent | 104c05c5284b7822d770ee51a7d91946c7e56d50 (diff) | |
download | gcc-e252b51ccde010cbd2a146485d8045103cd99533.zip gcc-e252b51ccde010cbd2a146485d8045103cd99533.tar.gz gcc-e252b51ccde010cbd2a146485d8045103cd99533.tar.bz2 |
Merge from trunk revision 104c05c5284b7822d770ee51a7d91946c7e56d50.
Diffstat (limited to 'gcc/c')
-rw-r--r-- | gcc/c/ChangeLog | 427 | ||||
-rw-r--r-- | gcc/c/c-aux-info.c | 4 | ||||
-rw-r--r-- | gcc/c/c-decl.c | 114 | ||||
-rw-r--r-- | gcc/c/c-fold.c | 8 | ||||
-rw-r--r-- | gcc/c/c-objc-common.c | 21 | ||||
-rw-r--r-- | gcc/c/c-parser.c | 1432 | ||||
-rw-r--r-- | gcc/c/c-tree.h | 9 | ||||
-rw-r--r-- | gcc/c/c-typeck.c | 614 | ||||
-rw-r--r-- | gcc/c/gimple-parser.c | 24 |
9 files changed, 2190 insertions, 463 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index e1da067..28fe7bc 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,430 @@ +2021-09-10 Jakub Jelinek <jakub@redhat.com> + + * c-parser.c (c_parser_conditional_expression): If omp_atomic_lhs and + cond.value is >, < or == with omp_atomic_lhs as one of the operands, + don't call build_conditional_expr, instead build a COND_EXPR directly. + (c_parser_binary_expression): Avoid calling parser_build_binary_op + if omp_atomic_lhs even in more cases for >, < or ==. + (c_parser_omp_atomic): Update function comment for OpenMP 5.1 atomics, + parse OpenMP 5.1 atomics and fail, compare and weak clauses, allow + acq_rel on atomic read/write and acq_rel/acquire clauses on update. + * c-typeck.c (build_binary_op): For flag_openmp only handle + MIN_EXPR/MAX_EXPR. + +2021-09-07 Marcel Vollweiler <marcel@codesourcery.com> + + * c-parser.c (c_parser_omp_flush): Parse 'seq_cst' clause on 'flush' + directive. + +2021-09-01 Iain Sandoe <iain@sandoe.co.uk> + + * c-decl.c (enum deprecated_states): Add unavailable state. + (merge_decls): Copy unavailability. + (quals_from_declspecs): Handle unavailable case. + (start_decl): Amend the logic handling suppression of nested + deprecation states to include unavailability. + (smallest_type_quals_location): Amend comment. + (grokdeclarator): Handle the unavailable deprecation state. + (declspecs_add_type): Set TREE_UNAVAILABLE from the decl specs. + * c-tree.h (struct c_declspecs): Add unavailable_p. + * c-typeck.c (build_component_ref): Handle unavailability. + (build_external_ref): Likewise. + +2021-09-01 Roger Sayle <roger@nextmovesoftware.com> + Joseph Myers <joseph@codesourcery.com> + + PR c/79412 + * c-decl.c (duplicate_decls): On significant mismatches, mark the + types of both (non-function) decls as error_mark_node, so that the + middle-end can see the code is malformed. + (free_attr_access_data): Don't process if the type has been set to + error_mark_node. + +2021-08-31 Marcel Vollweiler <marcel@codesourcery.com> + + * c-parser.c (c_parser_omp_clause_device): Parse device-modifiers 'device_num' + and 'ancestor' in 'target device' clauses. + +2021-08-23 Jakub Jelinek <jakub@redhat.com> + + * c-parser.c (c_parser_omp_clause_num_tasks, + c_parser_omp_clause_grainsize): Parse the optional strict: modifier. + +2021-08-22 Martin Uecker <muecker@gwdg.de> + + PR c/98397 + * c-typeck.c (comp_target_types): Change pedwarn to pedwarn_c11 + for pointers to arrays with qualifiers. + (build_conditional_expr): For C23 don't lose qualifiers for pointers + to arrays when the other pointer is a void pointer. Update warnings. + (convert_for_assignment): Update warnings for C2X when converting from + void* with qualifiers to a pointer to array with the same qualifiers. + +2021-08-20 Jakub Jelinek <jakub@redhat.com> + + * c-parser.c (c_parser_omp_error): New function. + (c_parser_pragma): Handle PRAGMA_OMP_ERROR. + +2021-08-20 Jakub Jelinek <jakub@redhat.com> + + * c-parser.c (c_parser_omp_clause_depend_sink): Reject spurious + comma at the end of list. + (c_parser_omp_requires): Likewise. + +2021-08-19 Jakub Jelinek <jakub@redhat.com> + + * c-parser.c (c_parser_omp_requires): Don't call + c_parser_peek_2nd_token and optionally consume token if current + token is CPP_EOF, CPP_PRAGMA_EOL or CPP_CLOSE_PAREN. + +2021-08-18 Jakub Jelinek <jakub@redhat.com> + + * c-parser.c (c_parser_omp_nothing): New function. + (c_parser_pragma): Handle PRAGMA_OMP_NOTHING. + +2021-08-18 Jakub Jelinek <jakub@redhat.com> + + * c-parser.c (c_parser_statement_after_labels): Add restart label + near the start of the function. If c_parser_pragma returns false, + goto restart. + (c_parser_pragma): For PRAGMA_OMP_CANCELLATION_POINT return what + c_parser_omp_cancellation_point returned. For PRAGMA_OMP_DECLARE + return what c_parser_omp_declare returned. Return true instead of + false after emitting errors that the directive is not allowed in + pragma_stmt context. + (c_parser_omp_ordered): Return true instead of + false after emitting errors that the directive is not allowed in + pragma_stmt context. + (c_parser_omp_target_update): Likewise. + (c_parser_omp_target_enter_data, c_parser_omp_target_exit_data): + Change return type from tree to bool, return false if the + directive should be ignored in pragma_stmt contexts. + (c_parser_omp_target): Adjust callers of c_parser_omp_target_*_data, + return their result directly. + (c_parser_omp_cancellation_point): Change return type from void to + bool, return false if the directive should be ignored in pragma_stmt + contexts. + (c_parser_omp_declare): Likewise. + +2021-08-17 Jakub Jelinek <jakub@redhat.com> + + * c-parser.c (OMP_SCOPE_CLAUSE_MASK): Define. + (c_parser_omp_scope): New function. + (c_parser_omp_construct): Handle PRAGMA_OMP_SCOPE. + +2021-08-12 Jakub Jelinek <jakub@redhat.com> + + * c-parser.c (c_parser_omp_clause_name): Parse filter clause name. + (c_parser_omp_clause_filter): New function. + (c_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_FILTER. + (OMP_MASKED_CLAUSE_MASK): Define. + (c_parser_omp_masked): New function. + (c_parser_omp_parallel): Handle parallel masked. + (c_parser_omp_construct): Handle PRAGMA_OMP_MASKED. + * c-typeck.c (c_finish_omp_clauses): Handle OMP_CLAUSE_FILTER. + +2021-08-12 Martin Uecker <muecker@gwdg.de> + + PR c/101838 + PR c/29970 + * c-typeck.c (c_expr_sizeof_type): Evaluate + size expressions for structs of variable size. + +2021-08-12 Tobias Burnus <tobias@codesourcery.com> + + * c-parser.c (c_parser_omp_clause_proc_bind): Accept + 'primary' as alias for 'master'. + +2021-08-10 Martin Uecker <muecker@gwdg.de> + + PR c/29970 + * c-typeck.c (c_expr_sizeof_expr): Evaluate + size expressions for structs of variable size. + +2021-08-06 Tamar Christina <tamar.christina@arm.com> + + * c-decl.c (c_simulate_enum_decl): Pass vec<> by pointer. + * c-tree.h (c_simulate_enum_decl): Likewise. + +2021-08-06 Martin Sebor <msebor@redhat.com> + + * c-parser.c (c_parser_declaration_or_fndef): Adjust by-value function + vec arguments to by-reference. + (c_finish_omp_declare_simd): Same. + (c_parser_compound_statement_nostart): Same. + (c_parser_for_statement): Same. + (c_parser_objc_methodprotolist): Same. + (c_parser_oacc_routine): Same. + (c_parser_omp_for_loop): Same. + (c_parser_omp_declare_simd): Same. + +2021-07-21 Thomas Schwinge <thomas@codesourcery.com> + Joseph Myers <joseph@codesourcery.com> + Cesar Philippidis <cesar@codesourcery.com> + + * c-parser.c (c_parser_omp_clause_name): Handle 'nohost'. + (c_parser_oacc_all_clauses): Handle 'PRAGMA_OACC_CLAUSE_NOHOST'. + (OACC_ROUTINE_CLAUSE_MASK): Add 'PRAGMA_OACC_CLAUSE_NOHOST'. + * c-typeck.c (c_finish_omp_clauses): Handle 'OMP_CLAUSE_NOHOST'. + +2021-07-20 Martin Sebor <msebor@redhat.com> + + * c-tree.h (c_build_function_call_vec): Adjust by-value argument to + by-const-reference. + * c-typeck.c (c_build_function_call_vec): Same. + +2021-07-15 Martin Sebor <msebor@redhat.com> + + PR c/101289 + PR c/97548 + * c-decl.c (get_parm_array_spec): Strip nops. + +2021-07-06 Martin Sebor <msebor@redhat.com> + + * c-objc-common.c (c_tree_printer): Remove support for %G and %K. + +2021-07-02 Jakub Jelinek <jakub@redhat.com> + + PR c/101297 + * c-parser.c (c_parser_omp_atomic): Consume comma only if it + appears before a CPP_NAME. + +2021-06-25 Martin Sebor <msebor@redhat.com> + + * c-decl.c (pop_scope): Replace direct uses of TREE_NO_WARNING with + warning_suppressed_p, suppress_warning, and copy_no_warning. + (diagnose_mismatched_decls): Same. + (duplicate_decls): Same. + (grokdeclarator): Same. + (finish_function): Same. + (c_write_global_declarations_1): Same. + * c-fold.c (c_fully_fold_internal): Same. + * c-parser.c (c_parser_expr_no_commas): Same. + (c_parser_postfix_expression): Same. + * c-typeck.c (array_to_pointer_conversion): Same. + (function_to_pointer_conversion): Same. + (default_function_array_conversion): Same. + (convert_lvalue_to_rvalue): Same. + (default_conversion): Same. + (build_indirect_ref): Same. + (build_function_call_vec): Same. + (build_atomic_assign): Same. + (build_unary_op): Same. + (c_finish_return): Same. + (emit_side_effect_warnings): Same. + (c_finish_stmt_expr): Same. + (c_omp_clause_copy_ctor): Same. + +2021-06-24 Jakub Jelinek <jakub@redhat.com> + + PR c/101176 + * c-parser.c (c_parser_has_attribute_expression): Set source range for + the result. + +2021-06-24 Jakub Jelinek <jakub@redhat.com> + + PR c/101171 + * c-typeck.c (build_c_cast): Don't call note_integer_operands on + error_mark_node. + +2021-06-24 Jakub Jelinek <jakub@redhat.com> + + * c-parser.c (omp_split_clauses): Pass C_ORT_OMP_TARGET instead of + C_ORT_OMP for clauses on target construct. + (OMP_TARGET_CLAUSE_MASK): Add in_reduction clause. + (c_parser_omp_target): For non-combined target add + map (always, tofrom:) clauses for OMP_CLAUSE_IN_REDUCTION. Pass + C_ORT_OMP_TARGET to c_finish_omp_clauses. + * c-typeck.c (handle_omp_array_sections): Adjust ort handling + for addition of C_ORT_OMP_TARGET and simplify, mapping clauses are + never present on C_ORT_*DECLARE_SIMD. + (c_finish_omp_clauses): Likewise. Handle OMP_CLAUSE_IN_REDUCTION + on C_ORT_OMP_TARGET, set OMP_CLAUSE_MAP_IN_REDUCTION on + corresponding map clauses. + +2021-06-21 Jakub Jelinek <jakub@redhat.com> + + PR inline-asm/100785 + * c-typeck.c (c_mark_addressable): Diagnose trying to make + bit-fields addressable. + +2021-06-15 Robin Dapp <rdapp@linux.ibm.com> + + * c-decl.c (merge_decls): Copy DECL_USER_ALIGN if DECL_ALIGN is + similar. + +2021-06-14 Tobias Burnus <tobias@codesourcery.com> + + PR c/100913 + * c-parser.c (c_parser_omp_clause_affinity): No need to set iterator + var in the error case. + +2021-06-07 Eric Botcazou <ebotcazou@adacore.com> + + PR c/100920 + * c-typeck.c (convert_for_assignment): Test fndecl_built_in_p to + spot built-in functions. + +2021-06-06 Jakub Jelinek <jakub@redhat.com> + + PR c/100902 + * c-parser.c (c_parser_omp_target): Call c_omp_adjust_map_clauses + even when target is combined with other constructs. + +2021-06-06 Eric Botcazou <ebotcazou@adacore.com> + + PR c/100920 + * c-decl.c (finish_struct): Fix thinko in previous change. + * c-typeck.c (convert_for_assignment): Do not warn on pointer + assignment and initialization for storage order purposes if the + RHS is a call to a DECL_IS_MALLOC function. + +2021-06-04 Martin Sebor <msebor@redhat.com> + + PR c/100783 + * c-objc-common.c (print_type): Handle erroneous types. + +2021-06-03 Jakub Jelinek <jakub@redhat.com> + + PR c++/100859 + * c-typeck.c (c_finish_omp_clauses): Move OMP_CLAUSE_AFFINITY + after depend only cases. + +2021-05-31 Richard Biener <rguenther@suse.de> + + PR c++/88601 + * c-decl.c (names_builtin_p): Handle RID_BUILTIN_SHUFFLEVECTOR. + * c-parser.c (c_parser_postfix_expression): Likewise. + +2021-05-28 Richard Biener <rguenther@suse.de> + + PR c/100803 + * gimple-parser.c (c_parser_gimple_paren_condition): Diagnose + invalid if conditions. + +2021-05-28 Jakub Jelinek <jakub@redhat.com> + + PR middle-end/99928 + * c-typeck.c (handle_omp_array_sections): Copy OMP_CLAUSE_MAP_IMPLICIT. + (c_finish_omp_clauses): Move not just OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT + marked clauses last, but also OMP_CLAUSE_MAP_IMPLICIT. Add + map_firstprivate_head bitmap, set it for GOMP_MAP_FIRSTPRIVATE_POINTER + maps and silently remove OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT if it is + present too. For OMP_CLAUSE_MAP_IMPLICIT silently remove the clause + if present in map_head, map_field_head or map_firstprivate_head + bitmaps. + +2021-05-28 Tobias Burnus <tobias@codesourcery.com> + + * c-parser.c (c_parser_omp_clause_affinity): New. + (c_parser_omp_clause_name, c_parser_omp_variable_list, + c_parser_omp_all_clauses, OMP_TASK_CLAUSE_MASK): Handle affinity clause. + * c-typeck.c (handle_omp_array_sections_1, handle_omp_array_sections, + c_finish_omp_clauses): Likewise. + +2021-05-26 Eric Botcazou <ebotcazou@adacore.com> + + PR c/100653 + * c-decl.c (finish_struct): Warn for a union containing an aggregate + field with a differing scalar storage order. + +2021-05-21 Jakub Jelinek <jakub@redhat.com> + + PR middle-end/99928 + * c-typeck.c (c_finish_omp_clauses): Move firstprivate clauses with + OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT to the end of the chain. Don't error + if a decl is mentioned both in map clause and in such firstprivate + clause unless OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT_TARGET is also set. + +2021-05-19 Jakub Jelinek <jakub@redhat.com> + + PR middle-end/99928 + * c-parser.c (c_parser_omp_master): Set OMP_MASTER_COMBINED on + master when combined with taskloop. + (c_parser_omp_parallel): Don't set OMP_PARALLEL_COMBINED on + parallel master when not combined with taskloop. + +2021-05-18 Richard Biener <rguenther@suse.de> + + PR c/100522 + * gimple-parser.c (c_parser_gimple_postfix_expression_after_primary): + Diagnose calls to non-functions. + (c_parser_gimple_statement): Diagnose unexpected assignment RHS. + +2021-05-17 Richard Biener <rguenther@suse.de> + + PR c/100625 + * gimple-parser.c (c_parser_gimple_label): Avoid building + a GIMPLE label with NULL label decl. + +2021-05-13 Martin Sebor <msebor@redhat.com> + + PR c/100550 + * c-decl.c (get_parm_array_spec): Avoid erroneous VLA bounds. + +2021-05-12 Marcel Vollweiler <marcel@codesourcery.com> + + * c-parser.c (c_parser_omp_clause_map): Support map-type-modifier + 'close'. + +2021-05-10 Martin Liska <mliska@suse.cz> + + * c-aux-info.c (affix_data_type): Use startswith + function instead of strncmp. + * c-typeck.c (build_function_call_vec): Likewise. + * gimple-parser.c (c_parser_gimple_parse_bb_spec): Likewise. + +2021-05-07 Eric Botcazou <ebotcazou@adacore.com> + + * c-typeck.c (build_unary_op) <ADDR_EXPR>: Do not issue an error + on the address of a pointer field in a record with reverse SSO. + +2021-05-04 Tobias Burnus <tobias@codesourcery.com> + + * c-typeck.c (c_finish_omp_clauses): Accept float + complex + for || and && reductions. + +2021-04-29 Joseph Myers <joseph@codesourcery.com> + + * c-typeck.c (function_types_compatible_p): For C2X, treat + unprototyped function as compatible with non-variadic prototyped + function even if some argument types are changed by the default + argument promotions. + +2021-04-15 Martin Sebor <msebor@redhat.com> + + PR c/99420 + PR c/99972 + * c-decl.c (pushdecl): Always propagate type attribute. + +2021-04-15 Richard Sandiford <richard.sandiford@arm.com> + + PR c/98852 + * c-typeck.c (c_common_type): Do not drop attributes that + affect type identity. + +2021-04-10 Jakub Jelinek <jakub@redhat.com> + + PR c/99990 + * c-decl.c (finish_decl): Don't overwrite TREE_TYPE of + error_mark_node. + +2021-03-25 Jakub Jelinek <jakub@redhat.com> + + PR c++/99565 + * c-typeck.c (build_conditional_expr): Pass OEP_ADDRESS_OF_SAME_FIELD + to operand_equal_p. + +2021-03-19 Jakub Jelinek <jakub@redhat.com> + + PR c/99588 + * c-typeck.c (mark_exp_read): Recognize what build_atomic_assign + with modifycode NOP_EXPR produces and mark the _Atomic var as read + if found. + (build_atomic_assign): For modifycode of NOP_EXPR, use COMPOUND_EXPRs + rather than STATEMENT_LIST. Otherwise call mark_exp_read on lhs. + Set TREE_SIDE_EFFECTS on the TARGET_EXPR. + 2021-03-15 Tobias Burnus <tobias@codesourcery.com> PR c++/99509 diff --git a/gcc/c/c-aux-info.c b/gcc/c/c-aux-info.c index bae5757..81860cb 100644 --- a/gcc/c/c-aux-info.c +++ b/gcc/c/c-aux-info.c @@ -67,12 +67,12 @@ affix_data_type (const char *param) for (;;) { - if (!strncmp (p, "volatile ", 9)) + if (startswith (p, "volatile ")) { p += 9; continue; } - if (!strncmp (p, "const ", 6)) + if (startswith (p, "const ")) { p += 6; continue; diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 3b2241b..771efa3 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -73,13 +73,16 @@ enum decl_context TYPENAME}; /* Typename (inside cast or sizeof) */ /* States indicating how grokdeclarator() should handle declspecs marked - with __attribute__((deprecated)). An object declared as - __attribute__((deprecated)) suppresses warnings of uses of other - deprecated items. */ + with __attribute__((deprecated)) or __attribute__((unavailable)). + An object declared as __attribute__((unavailable)) should suppress + any reports of being declared with unavailable or deprecated items. + An object declared as __attribute__((deprecated)) should suppress + warnings of uses of other deprecated items. */ enum deprecated_states { DEPRECATED_NORMAL, - DEPRECATED_SUPPRESS + DEPRECATED_SUPPRESS, + UNAVAILABLE_DEPRECATED_SUPPRESS }; @@ -1295,7 +1298,7 @@ pop_scope (void) case VAR_DECL: /* Warnings for unused variables. */ if ((!TREE_USED (p) || !DECL_READ_P (p)) - && !TREE_NO_WARNING (p) + && !warning_suppressed_p (p, OPT_Wunused_but_set_variable) && !DECL_IN_SYSTEM_HEADER (p) && DECL_NAME (p) && !DECL_ARTIFICIAL (p) @@ -2159,8 +2162,8 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, if (DECL_IN_SYSTEM_HEADER (newdecl) || DECL_IN_SYSTEM_HEADER (olddecl) - || TREE_NO_WARNING (newdecl) - || TREE_NO_WARNING (olddecl)) + || warning_suppressed_p (newdecl, OPT_Wpedantic) + || warning_suppressed_p (olddecl, OPT_Wpedantic)) return true; /* Allow OLDDECL to continue in use. */ if (variably_modified_type_p (newtype, NULL)) @@ -2620,6 +2623,9 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) SET_DECL_ALIGN (newdecl, DECL_ALIGN (olddecl)); DECL_USER_ALIGN (newdecl) |= DECL_USER_ALIGN (olddecl); } + else if (DECL_ALIGN (olddecl) == DECL_ALIGN (newdecl) + && DECL_USER_ALIGN (olddecl) != DECL_USER_ALIGN (newdecl)) + DECL_USER_ALIGN (newdecl) = 1; if (DECL_WARN_IF_NOT_ALIGN (olddecl) > DECL_WARN_IF_NOT_ALIGN (newdecl)) SET_DECL_WARN_IF_NOT_ALIGN (newdecl, @@ -2641,6 +2647,10 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) if (TREE_DEPRECATED (newdecl)) TREE_DEPRECATED (olddecl) = 1; + /* Merge unavailability. */ + if (TREE_UNAVAILABLE (newdecl)) + TREE_UNAVAILABLE (olddecl) = 1; + /* If a decl is in a system header and the other isn't, keep the one on the system header. Otherwise, keep source location of definition rather than declaration and of prototype rather than non-prototype unless that @@ -2953,7 +2963,18 @@ duplicate_decls (tree newdecl, tree olddecl) if (!diagnose_mismatched_decls (newdecl, olddecl, &newtype, &oldtype)) { /* Avoid `unused variable' and other warnings for OLDDECL. */ - TREE_NO_WARNING (olddecl) = 1; + suppress_warning (olddecl, OPT_Wunused); + /* If the types are completely different, poison them both with + error_mark_node. */ + if (TREE_CODE (TREE_TYPE (newdecl)) != TREE_CODE (TREE_TYPE (olddecl)) + && olddecl != error_mark_node + && seen_error ()) + { + if (TREE_CODE (olddecl) != FUNCTION_DECL) + TREE_TYPE (olddecl) = error_mark_node; + if (TREE_CODE (newdecl) != FUNCTION_DECL) + TREE_TYPE (newdecl) = error_mark_node; + } return false; } @@ -3263,11 +3284,10 @@ pushdecl (tree x) else thistype = type; b->u.type = TREE_TYPE (b->decl); - if (TREE_CODE (b->decl) == FUNCTION_DECL - && fndecl_built_in_p (b->decl)) - thistype - = build_type_attribute_variant (thistype, - TYPE_ATTRIBUTES (b->u.type)); + /* Propagate the type attributes to the decl. */ + thistype + = build_type_attribute_variant (thistype, + TYPE_ATTRIBUTES (b->u.type)); TREE_TYPE (b->decl) = thistype; bind (name, b->decl, scope, /*invisible=*/false, /*nested=*/true, locus); @@ -4879,6 +4899,7 @@ quals_from_declspecs (const struct c_declspecs *specs) && !specs->typedef_p && !specs->explicit_signed_p && !specs->deprecated_p + && !specs->unavailable_p && !specs->long_p && !specs->long_long_p && !specs->short_p @@ -5081,9 +5102,14 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs, tree expr = NULL_TREE; enum deprecated_states deprecated_state = DEPRECATED_NORMAL; - /* An object declared as __attribute__((deprecated)) suppresses + /* An object declared as __attribute__((unavailable)) suppresses + warnings and errors from __attribute__((deprecated/unavailable)) + components. + An object declared as __attribute__((deprecated)) suppresses warnings of uses of other deprecated items. */ - if (lookup_attribute ("deprecated", attributes)) + if (lookup_attribute ("unavailable", attributes)) + deprecated_state = UNAVAILABLE_DEPRECATED_SUPPRESS; + else if (lookup_attribute ("deprecated", attributes)) deprecated_state = DEPRECATED_SUPPRESS; decl = grokdeclarator (declarator, declspecs, @@ -5402,7 +5428,7 @@ finish_decl (tree decl, location_t init_loc, tree init, gcc_unreachable (); } - if (DECL_INITIAL (decl)) + if (DECL_INITIAL (decl) && DECL_INITIAL (decl) != error_mark_node) TREE_TYPE (DECL_INITIAL (decl)) = type; relayout_decl (decl); @@ -5857,9 +5883,13 @@ get_parm_array_spec (const struct c_parm *parm, tree attrs) spec += buf; break; } + else if (!INTEGRAL_TYPE_P (TREE_TYPE (nelts))) + /* Avoid invalid NELTS. */ + return attrs; /* Each variable VLA bound is represented by a dollar sign. */ spec += "$"; + STRIP_NOPS (nelts); vbchain = tree_cons (NULL_TREE, nelts, vbchain); } @@ -6216,7 +6246,7 @@ smallest_type_quals_location (const location_t *locations, set to indicate whether operands in *EXPR can be used in constant expressions. DEPRECATED_STATE is a deprecated_states value indicating whether - deprecation warnings should be suppressed. + deprecation/unavailability warnings should be suppressed. In the TYPENAME case, DECLARATOR is really an absolute declarator. It may also be so in the PARM case, for a prototype where the @@ -6346,8 +6376,14 @@ grokdeclarator (const struct c_declarator *declarator, if (decl_context == NORMAL && !funcdef_flag && current_scope->parm_flag) decl_context = PARM; - if (declspecs->deprecated_p && deprecated_state != DEPRECATED_SUPPRESS) - warn_deprecated_use (declspecs->type, declspecs->decl_attr); + if (deprecated_state != UNAVAILABLE_DEPRECATED_SUPPRESS) + { + if (declspecs->unavailable_p) + error_unavailable_use (declspecs->type, declspecs->decl_attr); + else if (declspecs->deprecated_p + && deprecated_state != DEPRECATED_SUPPRESS) + warn_deprecated_use (declspecs->type, declspecs->decl_attr); + } if ((decl_context == NORMAL || decl_context == FIELD) && current_scope == file_scope @@ -7538,10 +7574,7 @@ grokdeclarator (const struct c_declarator *declarator, FIELD_DECL, declarator->u.id.id, type); DECL_NONADDRESSABLE_P (decl) = bitfield; if (bitfield && !declarator->u.id.id) - { - TREE_NO_WARNING (decl) = 1; - DECL_PADDING_P (decl) = 1; - } + DECL_PADDING_P (decl) = 1; if (size_varies) C_DECL_VARIABLE_SIZE (decl) = 1; @@ -8851,6 +8884,22 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, = c_build_qualified_type (fmain_type, TYPE_QUALS (ftype)); } } + + /* Warn on problematic type punning for storage order purposes. */ + if (TREE_CODE (t) == UNION_TYPE + && TREE_CODE (field) == FIELD_DECL + && AGGREGATE_TYPE_P (TREE_TYPE (field))) + { + tree ftype = TREE_TYPE (field); + if (TREE_CODE (ftype) == ARRAY_TYPE) + ftype = strip_array_types (ftype); + if (RECORD_OR_UNION_TYPE_P (ftype) + && TYPE_REVERSE_STORAGE_ORDER (ftype) + != TYPE_REVERSE_STORAGE_ORDER (t)) + warning_at (DECL_SOURCE_LOCATION (field), + OPT_Wscalar_storage_order, + "type punning toggles scalar storage order"); + } } /* Now we have the truly final field list. @@ -9360,7 +9409,7 @@ build_enumerator (location_t decl_loc, location_t loc, tree c_simulate_enum_decl (location_t loc, const char *name, - vec<string_int_pair> values) + vec<string_int_pair> *values_ptr) { location_t saved_loc = input_location; input_location = loc; @@ -9370,6 +9419,7 @@ c_simulate_enum_decl (location_t loc, const char *name, tree value_chain = NULL_TREE; string_int_pair *value; + vec<string_int_pair> values = *values_ptr; unsigned int i; FOR_EACH_VEC_ELT (values, i, value) { @@ -10223,7 +10273,7 @@ finish_function (location_t end_loc) && targetm.warn_func_return (fndecl) && warning (OPT_Wreturn_type, "no return statement in function returning non-void")) - TREE_NO_WARNING (fndecl) = 1; + suppress_warning (fndecl, OPT_Wreturn_type); /* Complain about parameters that are only set, but never otherwise used. */ if (warn_unused_but_set_parameter) @@ -10238,7 +10288,7 @@ finish_function (location_t end_loc) && !DECL_READ_P (decl) && DECL_NAME (decl) && !DECL_ARTIFICIAL (decl) - && !TREE_NO_WARNING (decl)) + && !warning_suppressed_p (decl, OPT_Wunused_but_set_parameter)) warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wunused_but_set_parameter, "parameter %qD set but not used", decl); @@ -10538,6 +10588,7 @@ names_builtin_p (const char *name) case RID_BUILTIN_CONVERTVECTOR: case RID_BUILTIN_HAS_ATTRIBUTE: case RID_BUILTIN_SHUFFLE: + case RID_BUILTIN_SHUFFLEVECTOR: case RID_CHOOSE_EXPR: case RID_OFFSETOF: case RID_TYPES_COMPATIBLE_P: @@ -10782,6 +10833,8 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, specs->typespec_kind = spec.kind; if (TREE_DEPRECATED (type)) specs->deprecated_p = true; + if (TREE_UNAVAILABLE (type)) + specs->unavailable_p = true; /* Handle type specifier keywords. */ if (TREE_CODE (type) == IDENTIFIER_NODE @@ -12104,19 +12157,20 @@ c_write_global_declarations_1 (tree globals) { if (C_DECL_USED (decl)) { + /* TODO: Add OPT_Wundefined-inline. */ if (pedwarn (input_location, 0, "%q+F used but never defined", decl)) - TREE_NO_WARNING (decl) = 1; + suppress_warning (decl /* OPT_Wundefined-inline. */); } /* For -Wunused-function warn about unused static prototypes. */ else if (warn_unused_function && ! DECL_ARTIFICIAL (decl) - && ! TREE_NO_WARNING (decl)) + && ! warning_suppressed_p (decl, OPT_Wunused_function)) { if (warning (OPT_Wunused_function, "%q+F declared %<static%> but never defined", decl)) - TREE_NO_WARNING (decl) = 1; + suppress_warning (decl, OPT_Wunused_function); } } @@ -12187,7 +12241,7 @@ free_attr_access_data () attr_access::free_lang_data (attrs); tree fntype = TREE_TYPE (n->decl); - if (!fntype) + if (!fntype || fntype == error_mark_node) continue; tree attrs = TYPE_ATTRIBUTES (fntype); if (!attrs) diff --git a/gcc/c/c-fold.c b/gcc/c/c-fold.c index 68c74cc..0ebcb46 100644 --- a/gcc/c/c-fold.c +++ b/gcc/c/c-fold.c @@ -154,7 +154,7 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, tree orig_op0, orig_op1, orig_op2; bool op0_const = true, op1_const = true, op2_const = true; bool op0_const_self = true, op1_const_self = true, op2_const_self = true; - bool nowarning = TREE_NO_WARNING (expr); + bool nowarning = warning_suppressed_p (expr, OPT_Woverflow); bool unused_p; bool op0_lval = false; source_range old_range; @@ -670,13 +670,13 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, out: /* Some folding may introduce NON_LVALUE_EXPRs; all lvalue checks have been done by this point, so remove them again. */ - nowarning |= TREE_NO_WARNING (ret); + nowarning |= warning_suppressed_p (ret, OPT_Woverflow); STRIP_TYPE_NOPS (ret); - if (nowarning && !TREE_NO_WARNING (ret)) + if (nowarning && !warning_suppressed_p (ret, OPT_Woverflow)) { if (!CAN_HAVE_LOCATION_P (ret)) ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret); - TREE_NO_WARNING (ret) = 1; + suppress_warning (ret, OPT_Woverflow); } if (ret != expr) { diff --git a/gcc/c/c-objc-common.c b/gcc/c/c-objc-common.c index a68249d..cdb2242 100644 --- a/gcc/c/c-objc-common.c +++ b/gcc/c/c-objc-common.c @@ -185,6 +185,12 @@ get_aka_type (tree type) static void print_type (c_pretty_printer *cpp, tree t, bool *quoted) { + if (t == error_mark_node) + { + pp_string (cpp, _("{erroneous}")); + return; + } + gcc_assert (TYPE_P (t)); struct obstack *ob = pp_buffer (cpp)->obstack; char *p = (char *) obstack_base (ob); @@ -241,8 +247,6 @@ print_type (c_pretty_printer *cpp, tree t, bool *quoted) %D: a general decl, %E: an identifier or expression, %F: a function declaration, - %G: a Gimple statement, - %K: a CALL_EXPR, %T: a type. %V: a list of type qualifiers from a tree. %v: an explicit list of type qualifiers @@ -263,19 +267,6 @@ c_tree_printer (pretty_printer *pp, text_info *text, const char *spec, if (precision != 0 || wide) return false; - if (*spec == 'G') - { - percent_G_format (text); - return true; - } - - if (*spec == 'K') - { - t = va_arg (*text->args_ptr, tree); - percent_K_format (text, EXPR_LOCATION (t), TREE_BLOCK (t)); - return true; - } - if (*spec != 'v') { t = va_arg (*text->args_ptr, tree); diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 5cdeb21..d82c042 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1489,7 +1489,8 @@ static tree c_parser_std_attribute_specifier_sequence (c_parser *); static void c_parser_external_declaration (c_parser *); static void c_parser_asm_definition (c_parser *); static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool, - bool, bool, tree *, vec<c_token>, + bool, bool, tree * = NULL, + vec<c_token> * = NULL, bool have_attrs = false, tree attrs = NULL, struct oacc_routine_data * = NULL, @@ -1577,15 +1578,17 @@ static tree c_parser_omp_for_loop (location_t, c_parser *, enum tree_code, static void c_parser_omp_taskwait (c_parser *); static void c_parser_omp_taskyield (c_parser *); static void c_parser_omp_cancel (c_parser *); +static void c_parser_omp_nothing (c_parser *); enum pragma_context { pragma_external, pragma_struct, pragma_param, pragma_stmt, pragma_compound }; static bool c_parser_pragma (c_parser *, enum pragma_context, bool *); -static void c_parser_omp_cancellation_point (c_parser *, enum pragma_context); +static bool c_parser_omp_cancellation_point (c_parser *, enum pragma_context); static bool c_parser_omp_target (c_parser *, enum pragma_context, bool *); static void c_parser_omp_end_declare_target (c_parser *); -static void c_parser_omp_declare (c_parser *, enum pragma_context); +static bool c_parser_omp_declare (c_parser *, enum pragma_context); static void c_parser_omp_requires (c_parser *); +static bool c_parser_omp_error (c_parser *, enum pragma_context); static bool c_parser_omp_ordered (c_parser *, enum pragma_context, bool *); static void c_parser_oacc_routine (c_parser *, enum pragma_context); @@ -1774,13 +1777,12 @@ c_parser_external_declaration (c_parser *parser) an @interface or @protocol with prefix attributes). We can only tell which after parsing the declaration specifiers, if any, and the first declarator. */ - c_parser_declaration_or_fndef (parser, true, true, true, false, true, - NULL, vNULL); + c_parser_declaration_or_fndef (parser, true, true, true, false, true); break; } } -static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token>); +static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token> *); static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool); /* Build and add a DEBUG_BEGIN_STMT statement with location LOC. */ @@ -1890,11 +1892,15 @@ static void c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool static_assert_ok, bool empty_ok, bool nested, bool start_attr_ok, - tree *objc_foreach_object_declaration, - vec<c_token> omp_declare_simd_clauses, - bool have_attrs, tree attrs, - struct oacc_routine_data *oacc_routine_data, - bool *fallthru_attr_p) + tree *objc_foreach_object_declaration + /* = NULL */, + vec<c_token> *omp_declare_simd_clauses + /* = NULL */, + bool have_attrs /* = false */, + tree attrs /* = NULL_TREE */, + struct oacc_routine_data *oacc_routine_data + /* = NULL */, + bool *fallthru_attr_p /* = NULL */) { struct c_declspecs *specs; tree prefix_attrs; @@ -2150,7 +2156,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, C_DTR_NORMAL, &dummy); if (declarator == NULL) { - if (omp_declare_simd_clauses.exists ()) + if (omp_declare_simd_clauses) c_finish_omp_declare_simd (parser, NULL_TREE, NULL_TREE, omp_declare_simd_clauses); if (oacc_routine_data) @@ -2250,7 +2256,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, chainon (postfix_attrs, all_prefix_attrs)); if (!d) d = error_mark_node; - if (omp_declare_simd_clauses.exists ()) + if (omp_declare_simd_clauses) c_finish_omp_declare_simd (parser, d, NULL_TREE, omp_declare_simd_clauses); } @@ -2262,7 +2268,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, chainon (postfix_attrs, all_prefix_attrs)); if (!d) d = error_mark_node; - if (omp_declare_simd_clauses.exists ()) + if (omp_declare_simd_clauses) c_finish_omp_declare_simd (parser, d, NULL_TREE, omp_declare_simd_clauses); init_loc = c_parser_peek_token (parser)->location; @@ -2342,7 +2348,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, warn_parm_array_mismatch (lastloc, d, parms); } } - if (omp_declare_simd_clauses.exists ()) + if (omp_declare_simd_clauses) { tree parms = NULL_TREE; if (d && TREE_CODE (d) == FUNCTION_DECL) @@ -2496,9 +2502,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, while (c_parser_next_token_is_not (parser, CPP_EOF) && c_parser_next_token_is_not (parser, CPP_OPEN_BRACE)) c_parser_declaration_or_fndef (parser, false, false, false, - true, false, NULL, vNULL); + true, false); store_parm_decls (); - if (omp_declare_simd_clauses.exists ()) + if (omp_declare_simd_clauses) c_finish_omp_declare_simd (parser, current_function_decl, NULL_TREE, omp_declare_simd_clauses); if (oacc_routine_data) @@ -5699,7 +5705,7 @@ c_parser_compound_statement_nostart (c_parser *parser) bool fallthru_attr_p = false; c_parser_declaration_or_fndef (parser, true, !have_std_attrs, true, true, true, NULL, - vNULL, have_std_attrs, std_attrs, + NULL, have_std_attrs, std_attrs, NULL, &fallthru_attr_p); if (last_stmt && !fallthru_attr_p) @@ -5731,7 +5737,7 @@ c_parser_compound_statement_nostart (c_parser *parser) last_label = false; mark_valid_location_for_stdc_pragma (false); c_parser_declaration_or_fndef (parser, true, true, true, true, - true, NULL, vNULL); + true); /* Following the old parser, __extension__ does not disable this diagnostic. */ restore_extension_diagnostics (ext); @@ -6096,6 +6102,7 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p, if (c_parser_peek_token (parser)->type != CPP_OPEN_BRACE) add_debug_begin_stmt (loc); + restart: switch (c_parser_peek_token (parser)->type) { case CPP_OPEN_BRACE: @@ -6242,7 +6249,8 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p, c_parser_consume_token (parser); break; case CPP_PRAGMA: - c_parser_pragma (parser, pragma_stmt, if_p); + if (!c_parser_pragma (parser, pragma_stmt, if_p)) + goto restart; break; default: expr_stmt: @@ -6782,7 +6790,7 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll, || c_parser_nth_token_starts_std_attributes (parser, 1)) { c_parser_declaration_or_fndef (parser, true, true, true, true, true, - &object_expression, vNULL); + &object_expression); parser->objc_could_be_foreach_context = false; if (c_parser_next_token_is_keyword (parser, RID_IN)) @@ -6813,7 +6821,7 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll, ext = disable_extension_diagnostics (); c_parser_consume_token (parser); c_parser_declaration_or_fndef (parser, true, true, true, true, - true, &object_expression, vNULL); + true, &object_expression); parser->objc_could_be_foreach_context = false; restore_extension_diagnostics (ext); @@ -7558,7 +7566,7 @@ c_parser_expr_no_commas (c_parser *parser, struct c_expr *after, ret.original_code = MODIFY_EXPR; else { - TREE_NO_WARNING (ret.value) = 1; + suppress_warning (ret.value, OPT_Wparentheses); ret.original_code = ERROR_MARK; } ret.original_type = NULL; @@ -7655,10 +7663,21 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after, c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node; location_t loc1 = make_location (exp1.get_start (), exp1.src_range); location_t loc2 = make_location (exp2.get_start (), exp2.src_range); - ret.value = build_conditional_expr (colon_loc, cond.value, - cond.original_code == C_MAYBE_CONST_EXPR, - exp1.value, exp1.original_type, loc1, - exp2.value, exp2.original_type, loc2); + if (__builtin_expect (omp_atomic_lhs != NULL, 0) + && (TREE_CODE (cond.value) == GT_EXPR + || TREE_CODE (cond.value) == LT_EXPR + || TREE_CODE (cond.value) == EQ_EXPR) + && c_tree_equal (exp2.value, omp_atomic_lhs) + && (c_tree_equal (TREE_OPERAND (cond.value, 0), omp_atomic_lhs) + || c_tree_equal (TREE_OPERAND (cond.value, 1), omp_atomic_lhs))) + ret.value = build3_loc (colon_loc, COND_EXPR, TREE_TYPE (omp_atomic_lhs), + cond.value, exp1.value, exp2.value); + else + ret.value + = build_conditional_expr (colon_loc, cond.value, + cond.original_code == C_MAYBE_CONST_EXPR, + exp1.value, exp1.original_type, loc1, + exp2.value, exp2.original_type, loc2); ret.original_code = ERROR_MARK; if (exp1.value == error_mark_node || exp2.value == error_mark_node) ret.original_type = NULL; @@ -7841,15 +7860,27 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after, = convert_lvalue_to_rvalue (stack[sp].loc, \ stack[sp].expr, true, true); \ if (__builtin_expect (omp_atomic_lhs != NULL_TREE, 0) && sp == 1 \ - && c_parser_peek_token (parser)->type == CPP_SEMICOLON \ - && ((1 << stack[sp].prec) \ - & ((1 << PREC_BITOR) | (1 << PREC_BITXOR) | (1 << PREC_BITAND) \ - | (1 << PREC_SHIFT) | (1 << PREC_ADD) | (1 << PREC_MULT))) \ + && ((c_parser_next_token_is (parser, CPP_SEMICOLON) \ + && ((1 << stack[sp].prec) \ + & ((1 << PREC_BITOR) | (1 << PREC_BITXOR) \ + | (1 << PREC_BITAND) | (1 << PREC_SHIFT) \ + | (1 << PREC_ADD) | (1 << PREC_MULT) \ + | (1 << PREC_EQ)))) \ + || ((c_parser_next_token_is (parser, CPP_QUERY) \ + || (omp_atomic_lhs == void_list_node \ + && c_parser_next_token_is (parser, CPP_CLOSE_PAREN))) \ + && (stack[sp].prec == PREC_REL || stack[sp].prec == PREC_EQ)))\ && stack[sp].op != TRUNC_MOD_EXPR \ + && stack[sp].op != GE_EXPR \ + && stack[sp].op != LE_EXPR \ + && stack[sp].op != NE_EXPR \ && stack[0].expr.value != error_mark_node \ && stack[1].expr.value != error_mark_node \ - && (c_tree_equal (stack[0].expr.value, omp_atomic_lhs) \ - || c_tree_equal (stack[1].expr.value, omp_atomic_lhs))) \ + && (omp_atomic_lhs == void_list_node \ + || c_tree_equal (stack[0].expr.value, omp_atomic_lhs) \ + || c_tree_equal (stack[1].expr.value, omp_atomic_lhs) \ + || (stack[sp].op == EQ_EXPR \ + && c_parser_peek_2nd_token (parser)->keyword == RID_IF))) \ { \ tree t = make_node (stack[1].op); \ TREE_TYPE (t) = TREE_TYPE (stack[0].expr.value); \ @@ -8406,6 +8437,7 @@ c_parser_has_attribute_expression (c_parser *parser) { gcc_assert (c_parser_next_token_is_keyword (parser, RID_BUILTIN_HAS_ATTRIBUTE)); + location_t start = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); c_inhibit_evaluation_warnings++; @@ -8484,6 +8516,7 @@ c_parser_has_attribute_expression (c_parser *parser) parser->translate_strings_p = save_translate_strings_p; + location_t finish = c_parser_peek_token (parser)->location; if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) c_parser_consume_token (parser); else @@ -8512,6 +8545,7 @@ c_parser_has_attribute_expression (c_parser *parser) else result.value = boolean_false_node; + set_c_expr_source_range (&result, start, finish); return result; } @@ -9085,7 +9119,7 @@ c_parser_postfix_expression (c_parser *parser) c_parser_consume_token (parser); expr = c_parser_expression (parser); if (TREE_CODE (expr.value) == MODIFY_EXPR) - TREE_NO_WARNING (expr.value) = 1; + suppress_warning (expr.value, OPT_Wparentheses); if (expr.original_code != C_MAYBE_CONST_EXPR && expr.original_code != SIZEOF_EXPR) expr.original_code = ERROR_MARK; @@ -10000,6 +10034,44 @@ c_parser_postfix_expression (c_parser *parser) set_c_expr_source_range (&expr, loc, close_paren_loc); break; } + case RID_BUILTIN_SHUFFLEVECTOR: + { + vec<c_expr_t, va_gc> *cexpr_list; + unsigned int i; + c_expr_t *p; + location_t close_paren_loc; + + c_parser_consume_token (parser); + if (!c_parser_get_builtin_args (parser, + "__builtin_shufflevector", + &cexpr_list, false, + &close_paren_loc)) + { + expr.set_error (); + break; + } + + FOR_EACH_VEC_SAFE_ELT (cexpr_list, i, p) + *p = convert_lvalue_to_rvalue (loc, *p, true, true); + + if (vec_safe_length (cexpr_list) < 3) + { + error_at (loc, "wrong number of arguments to " + "%<__builtin_shuffle%>"); + expr.set_error (); + } + else + { + auto_vec<tree, 16> mask; + for (i = 2; i < cexpr_list->length (); ++i) + mask.safe_push ((*cexpr_list)[i].value); + expr.value = c_build_shufflevector (loc, (*cexpr_list)[0].value, + (*cexpr_list)[1].value, + mask); + } + set_c_expr_source_range (&expr, loc, close_paren_loc); + break; + } case RID_BUILTIN_CONVERTVECTOR: { location_t start_loc = loc; @@ -11236,7 +11308,7 @@ c_parser_objc_methodprotolist (c_parser *parser) } else c_parser_declaration_or_fndef (parser, false, false, true, - false, true, NULL, vNULL); + false, true); break; } } @@ -12301,7 +12373,7 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) "%<#pragma %s%> may only be used in compound " "statements", construct); c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); - return false; + return true; } goto bad_stmt; } @@ -12392,8 +12464,7 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) return false; case PRAGMA_OMP_CANCELLATION_POINT: - c_parser_omp_cancellation_point (parser, context); - return false; + return c_parser_omp_cancellation_point (parser, context); case PRAGMA_OMP_THREADPRIVATE: c_parser_omp_threadprivate (parser); @@ -12421,8 +12492,7 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) return false; case PRAGMA_OMP_DECLARE: - c_parser_omp_declare (parser, context); - return false; + return c_parser_omp_declare (parser, context); case PRAGMA_OMP_REQUIRES: if (context != pragma_external) @@ -12435,6 +12505,13 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) c_parser_omp_requires (parser); return false; + case PRAGMA_OMP_NOTHING: + c_parser_omp_nothing (parser); + return false; + + case PRAGMA_OMP_ERROR: + return c_parser_omp_error (parser, context); + case PRAGMA_OMP_ORDERED: return c_parser_omp_ordered (parser, context, if_p); @@ -12460,7 +12537,7 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) else c_parser_do_statement (parser, ivdep, unroll); } - return false; + return true; case PRAGMA_UNROLL: { @@ -12484,7 +12561,7 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) else c_parser_do_statement (parser, ivdep, unroll); } - return false; + return true; case PRAGMA_GCC_PCH_PREPROCESS: c_parser_error (parser, "%<#pragma GCC pch_preprocess%> must be first"); @@ -12601,7 +12678,9 @@ c_parser_omp_clause_name (c_parser *parser) switch (p[0]) { case 'a': - if (!strcmp ("aligned", p)) + if (!strcmp ("affinity", p)) + result = PRAGMA_OMP_CLAUSE_AFFINITY; + else if (!strcmp ("aligned", p)) result = PRAGMA_OMP_CLAUSE_ALIGNED; else if (!strcmp ("allocate", p)) result = PRAGMA_OMP_CLAUSE_ALLOCATE; @@ -12649,7 +12728,9 @@ c_parser_omp_clause_name (c_parser *parser) result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE; break; case 'f': - if (!strcmp ("final", p)) + if (!strcmp ("filter", p)) + result = PRAGMA_OMP_CLAUSE_FILTER; + else if (!strcmp ("final", p)) result = PRAGMA_OMP_CLAUSE_FINAL; else if (!strcmp ("finalize", p)) result = PRAGMA_OACC_CLAUSE_FINALIZE; @@ -12701,6 +12782,8 @@ c_parser_omp_clause_name (c_parser *parser) result = PRAGMA_OACC_CLAUSE_NO_CREATE; else if (!strcmp ("nogroup", p)) result = PRAGMA_OMP_CLAUSE_NOGROUP; + else if (!strcmp ("nohost", p)) + result = PRAGMA_OACC_CLAUSE_NOHOST; else if (!strcmp ("nontemporal", p)) result = PRAGMA_OMP_CLAUSE_NONTEMPORAL; else if (!strcmp ("notinbranch", p)) @@ -12900,7 +12983,7 @@ c_parser_omp_variable_list (c_parser *parser, while (1) { bool array_section_p = false; - if (kind == OMP_CLAUSE_DEPEND) + if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) { if (c_parser_next_token_is_not (parser, CPP_NAME) || c_parser_peek_token (parser)->id_kind != C_ID_ID) @@ -13040,6 +13123,7 @@ c_parser_omp_variable_list (c_parser *parser, t = build_component_ref (op_loc, t, ident, comp_loc); } /* FALLTHROUGH */ + case OMP_CLAUSE_AFFINITY: case OMP_CLAUSE_DEPEND: case OMP_CLAUSE_REDUCTION: case OMP_CLAUSE_IN_REDUCTION: @@ -13090,7 +13174,7 @@ c_parser_omp_variable_list (c_parser *parser, t = tree_cons (low_bound, length, t); } - if (kind == OMP_CLAUSE_DEPEND + if ((kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) && t != error_mark_node && parser->tokens_avail != 2) { @@ -13130,7 +13214,7 @@ c_parser_omp_variable_list (c_parser *parser, else list = tree_cons (t, NULL_TREE, list); - if (kind == OMP_CLAUSE_DEPEND) + if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) { parser->tokens = &parser->tokens_buf[0]; parser->tokens_avail = tokens_avail; @@ -13725,7 +13809,10 @@ c_parser_omp_clause_num_threads (c_parser *parser, tree list) } /* OpenMP 4.5: - num_tasks ( expression ) */ + num_tasks ( expression ) + + OpenMP 5.1: + num_tasks ( strict : expression ) */ static tree c_parser_omp_clause_num_tasks (c_parser *parser, tree list) @@ -13734,6 +13821,17 @@ c_parser_omp_clause_num_tasks (c_parser *parser, tree list) matching_parens parens; if (parens.require_open (parser)) { + bool strict = false; + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON + && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), + "strict") == 0) + { + strict = true; + c_parser_consume_token (parser); + c_parser_consume_token (parser); + } + location_t expr_loc = c_parser_peek_token (parser)->location; c_expr expr = c_parser_expr_no_commas (parser, NULL); expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); @@ -13763,6 +13861,7 @@ c_parser_omp_clause_num_tasks (c_parser *parser, tree list) c = build_omp_clause (num_tasks_loc, OMP_CLAUSE_NUM_TASKS); OMP_CLAUSE_NUM_TASKS_EXPR (c) = t; + OMP_CLAUSE_NUM_TASKS_STRICT (c) = strict; OMP_CLAUSE_CHAIN (c) = list; list = c; } @@ -13771,7 +13870,10 @@ c_parser_omp_clause_num_tasks (c_parser *parser, tree list) } /* OpenMP 4.5: - grainsize ( expression ) */ + grainsize ( expression ) + + OpenMP 5.1: + grainsize ( strict : expression ) */ static tree c_parser_omp_clause_grainsize (c_parser *parser, tree list) @@ -13780,6 +13882,17 @@ c_parser_omp_clause_grainsize (c_parser *parser, tree list) matching_parens parens; if (parens.require_open (parser)) { + bool strict = false; + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON + && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), + "strict") == 0) + { + strict = true; + c_parser_consume_token (parser); + c_parser_consume_token (parser); + } + location_t expr_loc = c_parser_peek_token (parser)->location; c_expr expr = c_parser_expr_no_commas (parser, NULL); expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); @@ -13809,6 +13922,7 @@ c_parser_omp_clause_grainsize (c_parser *parser, tree list) c = build_omp_clause (grainsize_loc, OMP_CLAUSE_GRAINSIZE); OMP_CLAUSE_GRAINSIZE_EXPR (c) = t; + OMP_CLAUSE_GRAINSIZE_STRICT (c) = strict; OMP_CLAUSE_CHAIN (c) = list; list = c; } @@ -13898,6 +14012,38 @@ c_parser_omp_clause_hint (c_parser *parser, tree list) return list; } +/* OpenMP 5.1: + filter ( integer-expression ) */ + +static tree +c_parser_omp_clause_filter (c_parser *parser, tree list) +{ + location_t hint_loc = c_parser_peek_token (parser)->location; + matching_parens parens; + if (parens.require_open (parser)) + { + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); + tree c, t = expr.value; + t = c_fully_fold (t, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + parens.skip_until_found_close (parser); + check_no_duplicate_clause (list, OMP_CLAUSE_FILTER, "filter"); + + c = build_omp_clause (hint_loc, OMP_CLAUSE_FILTER); + OMP_CLAUSE_FILTER_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + /* OpenMP 4.5: defaultmap ( tofrom : scalar ) @@ -15392,7 +15538,9 @@ c_parser_omp_clause_depend_sink (c_parser *parser, location_t clause_loc, OMP_CLAUSE_DEPEND_SINK_NEGATIVE (vec) = 1; } - if (c_parser_next_token_is_not (parser, CPP_COMMA)) + if (c_parser_next_token_is_not (parser, CPP_COMMA) + || c_parser_peek_2nd_token (parser)->type != CPP_NAME + || c_parser_peek_2nd_token (parser)->id_kind != C_ID_ID) break; c_parser_consume_token (parser); @@ -15508,6 +15656,67 @@ c_parser_omp_iterators (c_parser *parser) return ret ? ret : error_mark_node; } +/* OpenMP 5.0: + affinity ( [aff-modifier :] variable-list ) + aff-modifier: + iterator ( iterators-definition ) */ + +static tree +c_parser_omp_clause_affinity (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + tree nl, iterators = NULL_TREE; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + bool parse_iter = ((strcmp ("iterator", p) == 0) + && (c_parser_peek_2nd_token (parser)->type + == CPP_OPEN_PAREN)); + if (parse_iter) + { + unsigned n = 3; + parse_iter = (c_parser_check_balanced_raw_token_sequence (parser, &n) + && (c_parser_peek_nth_token_raw (parser, n)->type + == CPP_CLOSE_PAREN) + && (c_parser_peek_nth_token_raw (parser, n + 1)->type + == CPP_COLON)); + } + if (parse_iter) + { + iterators = c_parser_omp_iterators (parser); + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + { + if (iterators) + pop_scope (); + parens.skip_until_found_close (parser); + return list; + } + } + } + nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_AFFINITY, + list); + if (iterators) + { + tree block = pop_scope (); + if (iterators != error_mark_node) + { + TREE_VEC_ELT (iterators, 5) = block; + for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_DECL (c) = build_tree_list (iterators, + OMP_CLAUSE_DECL (c)); + } + } + + parens.skip_until_found_close (parser); + return nl; +} + + /* OpenMP 4.0: depend ( depend-kind: variable-list ) @@ -15643,54 +15852,83 @@ c_parser_omp_clause_depend (c_parser *parser, tree list) map-kind: alloc | to | from | tofrom | release | delete - map ( always [,] map-kind: variable-list ) */ + map ( always [,] map-kind: variable-list ) + + OpenMP 5.0: + map ( [map-type-modifier[,] ...] map-kind: variable-list ) + + map-type-modifier: + always | close */ static tree c_parser_omp_clause_map (c_parser *parser, tree list) { location_t clause_loc = c_parser_peek_token (parser)->location; enum gomp_map_kind kind = GOMP_MAP_TOFROM; - int always = 0; - enum c_id_kind always_id_kind = C_ID_NONE; - location_t always_loc = UNKNOWN_LOCATION; - tree always_id = NULL_TREE; tree nl, c; matching_parens parens; if (!parens.require_open (parser)) return list; - if (c_parser_next_token_is (parser, CPP_NAME)) + int pos = 1; + int map_kind_pos = 0; + while (c_parser_peek_nth_token_raw (parser, pos)->type == CPP_NAME) + { + if (c_parser_peek_nth_token_raw (parser, pos + 1)->type == CPP_COLON) + { + map_kind_pos = pos; + break; + } + + if (c_parser_peek_nth_token_raw (parser, pos + 1)->type == CPP_COMMA) + pos++; + pos++; + } + + int always_modifier = 0; + int close_modifier = 0; + for (int pos = 1; pos < map_kind_pos; ++pos) { c_token *tok = c_parser_peek_token (parser); + + if (tok->type == CPP_COMMA) + { + c_parser_consume_token (parser); + continue; + } + const char *p = IDENTIFIER_POINTER (tok->value); - always_id_kind = tok->id_kind; - always_loc = tok->location; - always_id = tok->value; if (strcmp ("always", p) == 0) { - c_token *sectok = c_parser_peek_2nd_token (parser); - if (sectok->type == CPP_COMMA) + if (always_modifier) { - c_parser_consume_token (parser); - c_parser_consume_token (parser); - always = 2; + c_parser_error (parser, "too many %<always%> modifiers"); + parens.skip_until_found_close (parser); + return list; } - else if (sectok->type == CPP_NAME) + always_modifier++; + } + else if (strcmp ("close", p) == 0) + { + if (close_modifier) { - p = IDENTIFIER_POINTER (sectok->value); - if (strcmp ("alloc", p) == 0 - || strcmp ("to", p) == 0 - || strcmp ("from", p) == 0 - || strcmp ("tofrom", p) == 0 - || strcmp ("release", p) == 0 - || strcmp ("delete", p) == 0) - { - c_parser_consume_token (parser); - always = 1; - } + c_parser_error (parser, "too many %<close%> modifiers"); + parens.skip_until_found_close (parser); + return list; } + close_modifier++; + } + else + { + c_parser_error (parser, "%<#pragma omp target%> with " + "modifier other than %<always%> or %<close%>" + "on %<map%> clause"); + parens.skip_until_found_close (parser); + return list; } + + c_parser_consume_token (parser); } if (c_parser_next_token_is (parser, CPP_NAME) @@ -15700,11 +15938,11 @@ c_parser_omp_clause_map (c_parser *parser, tree list) if (strcmp ("alloc", p) == 0) kind = GOMP_MAP_ALLOC; else if (strcmp ("to", p) == 0) - kind = always ? GOMP_MAP_ALWAYS_TO : GOMP_MAP_TO; + kind = always_modifier ? GOMP_MAP_ALWAYS_TO : GOMP_MAP_TO; else if (strcmp ("from", p) == 0) - kind = always ? GOMP_MAP_ALWAYS_FROM : GOMP_MAP_FROM; + kind = always_modifier ? GOMP_MAP_ALWAYS_FROM : GOMP_MAP_FROM; else if (strcmp ("tofrom", p) == 0) - kind = always ? GOMP_MAP_ALWAYS_TOFROM : GOMP_MAP_TOFROM; + kind = always_modifier ? GOMP_MAP_ALWAYS_TOFROM : GOMP_MAP_TOFROM; else if (strcmp ("release", p) == 0) kind = GOMP_MAP_RELEASE; else if (strcmp ("delete", p) == 0) @@ -15719,35 +15957,6 @@ c_parser_omp_clause_map (c_parser *parser, tree list) c_parser_consume_token (parser); c_parser_consume_token (parser); } - else if (always) - { - if (always_id_kind != C_ID_ID) - { - c_parser_error (parser, "expected identifier"); - parens.skip_until_found_close (parser); - return list; - } - - tree t = lookup_name (always_id); - if (t == NULL_TREE) - { - undeclared_variable (always_loc, always_id); - t = error_mark_node; - } - if (t != error_mark_node) - { - tree u = build_omp_clause (clause_loc, OMP_CLAUSE_MAP); - OMP_CLAUSE_DECL (u) = t; - OMP_CLAUSE_CHAIN (u) = list; - OMP_CLAUSE_SET_MAP_KIND (u, kind); - list = u; - } - if (always == 1) - { - parens.skip_until_found_close (parser); - return list; - } - } nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_MAP, list); @@ -15759,37 +15968,87 @@ c_parser_omp_clause_map (c_parser *parser, tree list) } /* OpenMP 4.0: - device ( expression ) */ + device ( expression ) + + OpenMP 5.0: + device ( [device-modifier :] integer-expression ) + + device-modifier: + ancestor | device_num */ static tree c_parser_omp_clause_device (c_parser *parser, tree list) { location_t clause_loc = c_parser_peek_token (parser)->location; - matching_parens parens; - if (parens.require_open (parser)) - { - location_t expr_loc = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); - tree c, t = expr.value; - t = c_fully_fold (t, false, NULL); + location_t expr_loc; + c_expr expr; + tree c, t; + bool ancestor = false; - parens.skip_until_found_close (parser); + matching_parens parens; + if (!parens.require_open (parser)) + return list; - if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + c_token *tok = c_parser_peek_token (parser); + const char *p = IDENTIFIER_POINTER (tok->value); + if (strcmp ("ancestor", p) == 0) { - c_parser_error (parser, "expected integer expression"); + /* A requires directive with the reverse_offload clause must be + specified. */ + if ((omp_requires_mask & OMP_REQUIRES_REVERSE_OFFLOAD) == 0) + { + error_at (tok->location, "%<ancestor%> device modifier not " + "preceded by %<requires%> directive " + "with %<reverse_offload%> clause"); + parens.skip_until_found_close (parser); + return list; + } + ancestor = true; + } + else if (strcmp ("device_num", p) == 0) + ; + else + { + error_at (tok->location, "expected %<ancestor%> or %<device_num%>"); + parens.skip_until_found_close (parser); return list; } + c_parser_consume_token (parser); + c_parser_consume_token (parser); + } + + expr_loc = c_parser_peek_token (parser)->location; + expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); + t = expr.value; + t = c_fully_fold (t, false, NULL); - check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE, "device"); + parens.skip_until_found_close (parser); - c = build_omp_clause (clause_loc, OMP_CLAUSE_DEVICE); - OMP_CLAUSE_DEVICE_ID (c) = t; - OMP_CLAUSE_CHAIN (c) = list; - list = c; + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; } + if (ancestor && TREE_CODE (t) == INTEGER_CST && !integer_onep (t)) + { + error_at (expr_loc, "the %<device%> clause expression must evaluate to " + "%<1%>"); + return list; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE, "device"); + c = build_omp_clause (clause_loc, OMP_CLAUSE_DEVICE); + + OMP_CLAUSE_DEVICE_ID (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + OMP_CLAUSE_DEVICE_ANCESTOR (c) = ancestor; + + list = c; return list; } @@ -15848,7 +16107,8 @@ c_parser_omp_clause_dist_schedule (c_parser *parser, tree list) proc_bind ( proc-bind-kind ) proc-bind-kind: - master | close | spread */ + primary | master | close | spread + where OpenMP 5.1 added 'primary' and deprecated the alias 'master'. */ static tree c_parser_omp_clause_proc_bind (c_parser *parser, tree list) @@ -15864,7 +16124,9 @@ c_parser_omp_clause_proc_bind (c_parser *parser, tree list) if (c_parser_next_token_is (parser, CPP_NAME)) { const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp ("master", p) == 0) + if (strcmp ("primary", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_PRIMARY; + else if (strcmp ("master", p) == 0) kind = OMP_CLAUSE_PROC_BIND_MASTER; else if (strcmp ("close", p) == 0) kind = OMP_CLAUSE_PROC_BIND_CLOSE; @@ -16143,6 +16405,11 @@ c_parser_oacc_all_clauses (c_parser *parser, omp_clause_mask mask, clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); c_name = "no_create"; break; + case PRAGMA_OACC_CLAUSE_NOHOST: + clauses = c_parser_oacc_simple_clause (here, OMP_CLAUSE_NOHOST, + clauses); + c_name = "nohost"; + break; case PRAGMA_OACC_CLAUSE_NUM_GANGS: clauses = c_parser_oacc_single_int_clause (parser, OMP_CLAUSE_NUM_GANGS, @@ -16291,6 +16558,10 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, clauses = c_parser_omp_clause_detach (parser, clauses); c_name = "detach"; break; + case PRAGMA_OMP_CLAUSE_FILTER: + clauses = c_parser_omp_clause_filter (parser, clauses); + c_name = "filter"; + break; case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE: clauses = c_parser_omp_clause_firstprivate (parser, clauses); c_name = "firstprivate"; @@ -16474,6 +16745,10 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, clauses = c_parser_omp_clause_linear (parser, clauses); c_name = "linear"; break; + case PRAGMA_OMP_CLAUSE_AFFINITY: + clauses = c_parser_omp_clause_affinity (parser, clauses); + c_name = "affinity"; + break; case PRAGMA_OMP_CLAUSE_DEPEND: clauses = c_parser_omp_clause_depend (parser, clauses); c_name = "depend"; @@ -17070,7 +17345,8 @@ c_parser_oacc_compute (location_t loc, c_parser *parser, ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_GANG) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WORKER) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SEQ) ) + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SEQ) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NOHOST) ) /* Parse an OpenACC routine directive. For named directives, we apply immediately to the named function. For unnamed ones we then parse @@ -17164,12 +17440,12 @@ c_parser_oacc_routine (c_parser *parser, enum pragma_context context) while (c_parser_next_token_is (parser, CPP_KEYWORD) && c_parser_peek_token (parser)->keyword == RID_EXTENSION); c_parser_declaration_or_fndef (parser, true, true, true, false, true, - NULL, vNULL, false, NULL, &data); + NULL, NULL, false, NULL, &data); restore_extension_diagnostics (ext); } else c_parser_declaration_or_fndef (parser, true, true, true, false, true, - NULL, vNULL, false, NULL, &data); + NULL, NULL, false, NULL, &data); } } @@ -17402,14 +17678,45 @@ c_parser_omp_allocate (location_t loc, c_parser *parser) capture-block: { v = x; update-stmt; } | { update-stmt; v = x; } | { v = x; x = expr; } - where x and v are lvalue expressions with scalar type. + OpenMP 5.1: + # pragma omp atomic compare new-line + conditional-update-atomic + + # pragma omp atomic compare capture new-line + conditional-update-capture-atomic + + conditional-update-atomic: + cond-expr-stmt | cond-update-stmt + cond-expr-stmt: + x = expr ordop x ? expr : x; + x = x ordop expr ? expr : x; + x = x == e ? d : x; + cond-update-stmt: + if (expr ordop x) { x = expr; } + if (x ordop expr) { x = expr; } + if (x == e) { x = d; } + ordop: + <, > + conditional-update-capture-atomic: + v = cond-expr-stmt + { v = x; cond-expr-stmt } + { cond-expr-stmt v = x; } + { v = x; cond-update-stmt } + { cond-update-stmt v = x; } + if (x == e) { x = d; } else { v = x; } + { r = x == e; if (r) { x = d; } } + { r = x == e; if (r) { x = d; } else { v = x; } } + + where x, r and v are lvalue expressions with scalar type, + expr, e and d are expressions with scalar type and e might be + the same as v. LOC is the location of the #pragma token. */ static void c_parser_omp_atomic (location_t loc, c_parser *parser, bool openacc) { - tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE; + tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE, r = NULL_TREE; tree lhs1 = NULL_TREE, rhs1 = NULL_TREE; tree stmt, orig_lhs, unfolded_lhs = NULL_TREE, unfolded_lhs1 = NULL_TREE; enum tree_code code = ERROR_MARK, opcode = NOP_EXPR; @@ -17421,10 +17728,18 @@ c_parser_omp_atomic (location_t loc, c_parser *parser, bool openacc) bool non_lvalue_p; bool first = true; tree clauses = NULL_TREE; + bool capture = false; + bool compare = false; + bool weak = false; + enum omp_memory_order fail = OMP_MEMORY_ORDER_UNSPECIFIED; + bool no_semicolon = false; + bool extra_scope = false; while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) { - if (!first && c_parser_next_token_is (parser, CPP_COMMA)) + if (!first + && c_parser_next_token_is (parser, CPP_COMMA) + && c_parser_peek_2nd_token (parser)->type == CPP_NAME) c_parser_consume_token (parser); first = false; @@ -17437,6 +17752,10 @@ c_parser_omp_atomic (location_t loc, c_parser *parser, bool openacc) enum tree_code new_code = ERROR_MARK; enum omp_memory_order new_memory_order = OMP_MEMORY_ORDER_UNSPECIFIED; + bool new_capture = false; + bool new_compare = false; + bool new_weak = false; + enum omp_memory_order new_fail = OMP_MEMORY_ORDER_UNSPECIFIED; if (!strcmp (p, "read")) new_code = OMP_ATOMIC_READ; @@ -17444,7 +17763,7 @@ c_parser_omp_atomic (location_t loc, c_parser *parser, bool openacc) new_code = NOP_EXPR; else if (!strcmp (p, "update")) new_code = OMP_ATOMIC; - else if (!strcmp (p, "capture")) + else if (openacc && !strcmp (p, "capture")) new_code = OMP_ATOMIC_CAPTURE_NEW; else if (openacc) { @@ -17452,6 +17771,47 @@ c_parser_omp_atomic (location_t loc, c_parser *parser, bool openacc) error_at (cloc, "expected %<read%>, %<write%>, %<update%>, " "or %<capture%> clause"); } + else if (!strcmp (p, "capture")) + new_capture = true; + else if (!strcmp (p, "compare")) + new_compare = true; + else if (!strcmp (p, "weak")) + new_weak = true; + else if (!strcmp (p, "fail")) + { + matching_parens parens; + + c_parser_consume_token (parser); + if (!parens.require_open (parser)) + continue; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *q + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + if (!strcmp (q, "seq_cst")) + new_fail = OMP_MEMORY_ORDER_SEQ_CST; + else if (!strcmp (q, "acquire")) + new_fail = OMP_MEMORY_ORDER_ACQUIRE; + else if (!strcmp (q, "relaxed")) + new_fail = OMP_MEMORY_ORDER_RELAXED; + } + + if (new_fail != OMP_MEMORY_ORDER_UNSPECIFIED) + { + c_parser_consume_token (parser); + if (fail != OMP_MEMORY_ORDER_UNSPECIFIED) + error_at (cloc, "too many %qs clauses", "fail"); + else + fail = new_fail; + } + else + c_parser_error (parser, "expected %<seq_cst%>, %<acquire%> " + "or %<relaxed%>"); + parens.skip_until_found_close (parser); + continue; + } else if (!strcmp (p, "seq_cst")) new_memory_order = OMP_MEMORY_ORDER_SEQ_CST; else if (!strcmp (p, "acq_rel")) @@ -17472,8 +17832,9 @@ c_parser_omp_atomic (location_t loc, c_parser *parser, bool openacc) { p = NULL; error_at (cloc, "expected %<read%>, %<write%>, %<update%>, " - "%<capture%>, %<seq_cst%>, %<acq_rel%>, " - "%<release%>, %<relaxed%> or %<hint%> clause"); + "%<capture%>, %<compare%>, %<weak%>, %<fail%>, " + "%<seq_cst%>, %<acq_rel%>, %<release%>, " + "%<relaxed%> or %<hint%> clause"); } if (p) { @@ -17496,6 +17857,27 @@ c_parser_omp_atomic (location_t loc, c_parser *parser, bool openacc) else memory_order = new_memory_order; } + else if (new_capture) + { + if (capture) + error_at (cloc, "too many %qs clauses", "capture"); + else + capture = true; + } + else if (new_compare) + { + if (compare) + error_at (cloc, "too many %qs clauses", "compare"); + else + compare = true; + } + else if (new_weak) + { + if (weak) + error_at (cloc, "too many %qs clauses", "weak"); + else + weak = true; + } c_parser_consume_token (parser); continue; } @@ -17506,6 +17888,30 @@ c_parser_omp_atomic (location_t loc, c_parser *parser, bool openacc) if (code == ERROR_MARK) code = OMP_ATOMIC; + if (capture) + { + if (code != OMP_ATOMIC) + error_at (loc, "%qs clause is incompatible with %<read%> or %<write%> " + "clauses", "capture"); + else + code = OMP_ATOMIC_CAPTURE_NEW; + } + if (compare && code != OMP_ATOMIC && code != OMP_ATOMIC_CAPTURE_NEW) + { + error_at (loc, "%qs clause is incompatible with %<read%> or %<write%> " + "clauses", "compare"); + compare = false; + } + if (fail != OMP_MEMORY_ORDER_UNSPECIFIED && !compare) + { + error_at (loc, "%qs clause requires %qs clause", "fail", "compare"); + fail = OMP_MEMORY_ORDER_UNSPECIFIED; + } + if (weak && !compare) + { + error_at (loc, "%qs clause requires %qs clause", "weak", "compare"); + weak = false; + } if (openacc) memory_order = OMP_MEMORY_ORDER_RELAXED; else if (memory_order == OMP_MEMORY_ORDER_UNSPECIFIED) @@ -17530,7 +17936,6 @@ c_parser_omp_atomic (location_t loc, c_parser *parser, bool openacc) memory_order = OMP_MEMORY_ORDER_ACQUIRE; break; case NOP_EXPR: /* atomic write */ - case OMP_ATOMIC: memory_order = OMP_MEMORY_ORDER_RELEASE; break; default: @@ -17546,36 +17951,32 @@ c_parser_omp_atomic (location_t loc, c_parser *parser, bool openacc) switch (code) { case OMP_ATOMIC_READ: - if (memory_order == OMP_MEMORY_ORDER_ACQ_REL - || memory_order == OMP_MEMORY_ORDER_RELEASE) + if (memory_order == OMP_MEMORY_ORDER_RELEASE) { error_at (loc, "%<#pragma omp atomic read%> incompatible with " - "%<acq_rel%> or %<release%> clauses"); + "%<release%> clause"); memory_order = OMP_MEMORY_ORDER_SEQ_CST; } + else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL) + memory_order = OMP_MEMORY_ORDER_ACQUIRE; break; case NOP_EXPR: /* atomic write */ - if (memory_order == OMP_MEMORY_ORDER_ACQ_REL - || memory_order == OMP_MEMORY_ORDER_ACQUIRE) + if (memory_order == OMP_MEMORY_ORDER_ACQUIRE) { error_at (loc, "%<#pragma omp atomic write%> incompatible with " - "%<acq_rel%> or %<acquire%> clauses"); - memory_order = OMP_MEMORY_ORDER_SEQ_CST; - } - break; - case OMP_ATOMIC: - /* case OMP_ATOMIC_CAPTURE_NEW: - or update to OpenMP 5.1 */ - if (memory_order == OMP_MEMORY_ORDER_ACQ_REL - || memory_order == OMP_MEMORY_ORDER_ACQUIRE) - { - error_at (loc, "%<#pragma omp atomic update%> incompatible with " - "%<acq_rel%> or %<acquire%> clauses"); + "%<acquire%> clause"); memory_order = OMP_MEMORY_ORDER_SEQ_CST; } + else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL) + memory_order = OMP_MEMORY_ORDER_RELEASE; break; default: break; } + if (fail != OMP_MEMORY_ORDER_UNSPECIFIED) + memory_order + = (enum omp_memory_order) (memory_order + | (fail << OMP_FAIL_MEMORY_ORDER_SHIFT)); switch (code) { @@ -17624,6 +18025,9 @@ c_parser_omp_atomic (location_t loc, c_parser *parser, bool openacc) c_parser_consume_token (parser); structured_block = true; } + else if (compare + && c_parser_next_token_is_keyword (parser, RID_IF)) + break; else { v = c_parser_cast_expression (parser, NULL).value; @@ -17635,6 +18039,12 @@ c_parser_omp_atomic (location_t loc, c_parser *parser, bool openacc) v = non_lvalue (v); if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) goto saw_error; + if (compare && c_parser_next_token_is_keyword (parser, RID_IF)) + { + eloc = c_parser_peek_token (parser)->location; + error_at (eloc, "expected expression"); + goto saw_error; + } } break; default: @@ -17644,6 +18054,179 @@ c_parser_omp_atomic (location_t loc, c_parser *parser, bool openacc) /* For structured_block case we don't know yet whether old or new x should be captured. */ restart: + if (compare && c_parser_next_token_is_keyword (parser, RID_IF)) + { + c_parser_consume_token (parser); + + matching_parens parens; + if (!parens.require_open (parser)) + goto saw_error; + eloc = c_parser_peek_token (parser)->location; + c_expr cmp_expr; + if (r) + { + cmp_expr = c_parser_cast_expression (parser, NULL); + cmp_expr = default_function_array_conversion (eloc, cmp_expr); + } + else + cmp_expr = c_parser_binary_expression (parser, NULL, void_list_node); + parens.skip_until_found_close (parser); + if (cmp_expr.value == error_mark_node) + goto saw_error; + if (r) + { + if (!c_tree_equal (cmp_expr.value, unfolded_lhs)) + goto bad_if; + cmp_expr.value = rhs1; + rhs1 = NULL_TREE; + gcc_assert (TREE_CODE (cmp_expr.value) == EQ_EXPR); + } + if (TREE_CODE (cmp_expr.value) == EQ_EXPR) + ; + else if (!structured_block && code == OMP_ATOMIC_CAPTURE_NEW) + { + error_at (EXPR_LOC_OR_LOC (cmp_expr.value, eloc), + "expected %<==%> comparison in %<if%> condition"); + goto saw_error; + } + else if (TREE_CODE (cmp_expr.value) != GT_EXPR + && TREE_CODE (cmp_expr.value) != LT_EXPR) + { + error_at (EXPR_LOC_OR_LOC (cmp_expr.value, eloc), + "expected %<==%>, %<<%> or %<>%> comparison in %<if%> " + "condition"); + goto saw_error; + } + if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) + goto saw_error; + + extra_scope = true; + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_cast_expression (parser, NULL); + lhs = expr.value; + expr = default_function_array_conversion (eloc, expr); + unfolded_lhs = expr.value; + lhs = c_fully_fold (lhs, false, NULL, true); + orig_lhs = lhs; + if (lhs == error_mark_node) + goto saw_error; + if (!lvalue_p (unfolded_lhs)) + lhs = non_lvalue (lhs); + if (!c_parser_next_token_is (parser, CPP_EQ)) + { + c_parser_error (parser, "expected %<=%>"); + goto saw_error; + } + c_parser_consume_token (parser); + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_expr_no_commas (parser, NULL); + rhs1 = expr.value; + + if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) + goto saw_error; + + if (!c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>")) + goto saw_error; + + extra_scope = false; + no_semicolon = true; + + if (c_tree_equal (TREE_OPERAND (cmp_expr.value, 0), unfolded_lhs)) + { + if (TREE_CODE (cmp_expr.value) == EQ_EXPR) + { + opcode = COND_EXPR; + rhs = c_fully_fold (TREE_OPERAND (cmp_expr.value, 1), + false, NULL, true); + rhs1 = c_fully_fold (rhs1, false, NULL, true); + } + else if (c_tree_equal (TREE_OPERAND (cmp_expr.value, 1), rhs1)) + { + opcode = (TREE_CODE (cmp_expr.value) == GT_EXPR + ? MIN_EXPR : MAX_EXPR); + rhs = c_fully_fold (rhs1, false, NULL, true); + rhs1 = c_fully_fold (TREE_OPERAND (cmp_expr.value, 0), + false, NULL, true); + } + else + goto bad_if; + } + else if (TREE_CODE (cmp_expr.value) == EQ_EXPR) + goto bad_if; + else if (c_tree_equal (TREE_OPERAND (cmp_expr.value, 1), unfolded_lhs) + && c_tree_equal (TREE_OPERAND (cmp_expr.value, 0), rhs1)) + { + opcode = (TREE_CODE (cmp_expr.value) == GT_EXPR + ? MAX_EXPR : MIN_EXPR); + rhs = c_fully_fold (rhs1, false, NULL, true); + rhs1 = c_fully_fold (TREE_OPERAND (cmp_expr.value, 1), + false, NULL, true); + } + else + { + bad_if: + c_parser_error (parser, + "invalid form of %<#pragma omp atomic compare%>"); + goto saw_error; + } + + if (c_parser_next_token_is_keyword (parser, RID_ELSE)) + { + if (code != OMP_ATOMIC_CAPTURE_NEW + || (structured_block && r == NULL_TREE) + || TREE_CODE (cmp_expr.value) != EQ_EXPR) + { + eloc = c_parser_peek_token (parser)->location; + error_at (eloc, "unexpected %<else%>"); + goto saw_error; + } + + c_parser_consume_token (parser); + + if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) + goto saw_error; + + extra_scope = true; + v = c_parser_cast_expression (parser, NULL).value; + non_lvalue_p = !lvalue_p (v); + v = c_fully_fold (v, false, NULL, true); + if (v == error_mark_node) + goto saw_error; + if (non_lvalue_p) + v = non_lvalue (v); + if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) + goto saw_error; + + expr = c_parser_expr_no_commas (parser, NULL); + + if (!c_tree_equal (expr.value, unfolded_lhs)) + goto bad_if; + + if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) + goto saw_error; + + if (!c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>")) + goto saw_error; + + extra_scope = false; + code = OMP_ATOMIC_CAPTURE_OLD; + if (r == NULL_TREE) + /* Signal to c_finish_omp_atomic that in + if (x == e) { x = d; } else { v = x; } + case the store to v should be conditional. */ + r = void_list_node; + } + else if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block) + { + c_parser_require_keyword (parser, RID_ELSE, "expected %<else%>"); + goto saw_error; + } + else if (code == OMP_ATOMIC_CAPTURE_NEW + && r != NULL_TREE + && v == NULL_TREE) + code = OMP_ATOMIC; + goto stmt_done; + } eloc = c_parser_peek_token (parser)->location; expr = c_parser_cast_expression (parser, NULL); lhs = expr.value; @@ -17653,9 +18236,14 @@ restart: orig_lhs = lhs; switch (TREE_CODE (lhs)) { + invalid_compare: + error_at (eloc, "invalid form of %<pragma omp atomic compare%>"); + /* FALLTHRU */ case ERROR_MARK: saw_error: c_parser_skip_to_end_of_block_or_statement (parser); + if (extra_scope && c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + c_parser_consume_token (parser); if (structured_block) { if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) @@ -17678,6 +18266,8 @@ restart: unfolded_lhs = NULL_TREE; opcode = PLUS_EXPR; rhs = integer_one_node; + if (compare) + goto invalid_compare; break; case POSTDECREMENT_EXPR: @@ -17689,6 +18279,8 @@ restart: unfolded_lhs = NULL_TREE; opcode = MINUS_EXPR; rhs = integer_one_node; + if (compare) + goto invalid_compare; break; case COMPOUND_EXPR: @@ -17718,6 +18310,8 @@ restart: && !structured_block && TREE_CODE (orig_lhs) == COMPOUND_EXPR) code = OMP_ATOMIC_CAPTURE_OLD; + if (compare) + goto invalid_compare; break; } if (TREE_CODE (TREE_OPERAND (lhs, 1)) == TRUTH_NOT_EXPR @@ -17733,6 +18327,8 @@ restart: && !structured_block && TREE_CODE (orig_lhs) == COMPOUND_EXPR) code = OMP_ATOMIC_CAPTURE_OLD; + if (compare) + goto invalid_compare; break; } } @@ -17740,6 +18336,11 @@ restart: default: if (!lvalue_p (unfolded_lhs)) lhs = non_lvalue (lhs); + if (compare && !c_parser_next_token_is (parser, CPP_EQ)) + { + c_parser_error (parser, "expected %<=%>"); + goto saw_error; + } switch (c_parser_peek_token (parser)->type) { case CPP_MULT_EQ: @@ -17786,6 +18387,8 @@ restart: case BIT_AND_EXPR: case BIT_IOR_EXPR: case BIT_XOR_EXPR: + if (compare) + break; if (c_tree_equal (TREE_OPERAND (rhs1, 0), unfolded_lhs)) { opcode = TREE_CODE (rhs1); @@ -17806,6 +18409,78 @@ restart: goto stmt_done; } break; + case COND_EXPR: + if (!compare) + break; + if (TREE_CODE (TREE_OPERAND (rhs1, 0)) != GT_EXPR + && TREE_CODE (TREE_OPERAND (rhs1, 0)) != LT_EXPR + && TREE_CODE (TREE_OPERAND (rhs1, 0)) != EQ_EXPR) + break; + if (!TREE_OPERAND (rhs1, 1)) + break; + if (!c_tree_equal (TREE_OPERAND (rhs1, 2), unfolded_lhs)) + break; + if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0), + unfolded_lhs)) + { + if (TREE_CODE (TREE_OPERAND (rhs1, 0)) == EQ_EXPR) + { + opcode = COND_EXPR; + rhs = c_fully_fold (TREE_OPERAND (TREE_OPERAND (rhs1, + 0), 1), + false, NULL, true); + rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 1), false, + NULL, true); + goto stmt_done; + } + if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1), + TREE_OPERAND (rhs1, 1))) + { + opcode = (TREE_CODE (TREE_OPERAND (rhs1, 0)) == GT_EXPR + ? MIN_EXPR : MAX_EXPR); + rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL, + true); + rhs1 = c_fully_fold (TREE_OPERAND (TREE_OPERAND (rhs1, + 0), 0), + false, NULL, true); + goto stmt_done; + } + } + else if (TREE_CODE (TREE_OPERAND (rhs1, 0)) == EQ_EXPR) + break; + else if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1), + unfolded_lhs)) + { + if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0), + TREE_OPERAND (rhs1, 1))) + { + opcode = (TREE_CODE (TREE_OPERAND (rhs1, 0)) == GT_EXPR + ? MAX_EXPR : MIN_EXPR); + rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL, + true); + rhs1 = c_fully_fold (TREE_OPERAND (TREE_OPERAND (rhs1, + 0), 1), + false, NULL, true); + goto stmt_done; + } + } + break; + case EQ_EXPR: + if (!compare + || code != OMP_ATOMIC_CAPTURE_NEW + || !structured_block + || v + || r) + break; + if (c_parser_next_token_is (parser, CPP_SEMICOLON) + && c_parser_peek_2nd_token (parser)->keyword == RID_IF) + { + r = lhs; + lhs = NULL_TREE; + c_parser_consume_token (parser); + goto restart; + } + break; case ERROR_MARK: goto saw_error; default: @@ -17854,10 +18529,12 @@ restart: break; } stmt_done: - if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW) + if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW && r == NULL_TREE) { - if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) + if (!no_semicolon + && !c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) goto saw_error; + no_semicolon = false; v = c_parser_cast_expression (parser, NULL).value; non_lvalue_p = !lvalue_p (v); v = c_fully_fold (v, false, NULL, true); @@ -17880,10 +18557,16 @@ stmt_done: } if (structured_block) { - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + if (!no_semicolon) + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>"); } done: + if (weak && opcode != COND_EXPR) + { + error_at (loc, "%<weak%> clause requires atomic equality comparison"); + weak = false; + } if (unfolded_lhs && unfolded_lhs1 && !c_tree_equal (unfolded_lhs, unfolded_lhs1)) { @@ -17892,12 +18575,12 @@ done: stmt = error_mark_node; } else - stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1, - swapped, memory_order); + stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1, r, + swapped, memory_order, weak); if (stmt != error_mark_node) add_stmt (stmt); - if (!structured_block) + if (!structured_block && !no_semicolon) c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); } @@ -18084,7 +18767,9 @@ c_parser_omp_flush (c_parser *parser) const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (!strcmp (p, "acq_rel")) + if (!strcmp (p, "seq_cst")) + mo = MEMMODEL_SEQ_CST; + else if (!strcmp (p, "acq_rel")) mo = MEMMODEL_ACQ_REL; else if (!strcmp (p, "release")) mo = MEMMODEL_RELEASE; @@ -18092,7 +18777,8 @@ c_parser_omp_flush (c_parser *parser) mo = MEMMODEL_ACQUIRE; else error_at (c_parser_peek_token (parser)->location, - "expected %<acq_rel%>, %<release%> or %<acquire%>"); + "expected %<seq_cst%>, %<acq_rel%>, %<release%> or " + "%<acquire%>"); c_parser_consume_token (parser); } if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) @@ -18274,8 +18960,7 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, vec_safe_push (for_block, c_begin_compound_stmt (true)); this_pre_body = push_stmt_list (); c_in_omp_for = true; - c_parser_declaration_or_fndef (parser, true, true, true, true, true, - NULL, vNULL); + c_parser_declaration_or_fndef (parser, true, true, true, true, true); c_in_omp_for = false; if (this_pre_body) { @@ -18595,7 +19280,9 @@ omp_split_clauses (location_t loc, enum tree_code code, c_omp_split_clauses (loc, code, mask, clauses, cclauses); for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++) if (cclauses[i]) - cclauses[i] = c_finish_omp_clauses (cclauses[i], C_ORT_OMP); + cclauses[i] = c_finish_omp_clauses (cclauses[i], + i == C_OMP_CLAUSE_SPLIT_TARGET + ? C_ORT_OMP_TARGET : C_ORT_OMP); } /* OpenMP 5.0: @@ -18826,6 +19513,7 @@ c_parser_omp_master (location_t loc, c_parser *parser, if (ret == NULL_TREE) return ret; ret = c_finish_omp_master (loc, block); + OMP_MASTER_COMBINED (ret) = 1; return ret; } } @@ -18847,6 +19535,70 @@ c_parser_omp_master (location_t loc, c_parser *parser, if_p)); } +/* OpenMP 5.1: + # pragma omp masked masked-clauses new-line + structured-block + + LOC is the location of the #pragma token. +*/ + +#define OMP_MASKED_CLAUSE_MASK \ + (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FILTER) + +static tree +c_parser_omp_masked (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses, + bool *if_p) +{ + tree block, clauses, ret; + + strcat (p_name, " masked"); + mask |= OMP_MASKED_CLAUSE_MASK; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + if (strcmp (p, "taskloop") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + + c_parser_consume_token (parser); + if (!flag_openmp) /* flag_openmp_simd */ + return c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses, + if_p); + block = c_begin_compound_stmt (true); + ret = c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses, + if_p); + block = c_end_compound_stmt (loc, block, true); + if (ret == NULL_TREE) + return ret; + ret = c_finish_omp_masked (loc, block, + cclauses[C_OMP_CLAUSE_SPLIT_MASKED]); + OMP_MASKED_COMBINED (ret) = 1; + return ret; + } + } + if (!flag_openmp) /* flag_openmp_simd */ + { + c_parser_skip_to_pragma_eol (parser, false); + return NULL_TREE; + } + + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); + if (cclauses) + { + omp_split_clauses (loc, OMP_MASKED, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_MASKED]; + } + + return c_finish_omp_masked (loc, c_parser_omp_structured_block (parser, + if_p), + clauses); +} + /* OpenMP 2.5: # pragma omp ordered new-line structured-block @@ -18895,7 +19647,7 @@ c_parser_omp_ordered (c_parser *parser, enum pragma_context context, "%<#pragma omp ordered%> with %<depend%> clause may " "only be used in compound statements"); c_parser_skip_to_pragma_eol (parser, false); - return false; + return true; } tree clauses @@ -19109,7 +19861,36 @@ c_parser_omp_parallel (location_t loc, c_parser *parser, else if (c_parser_next_token_is (parser, CPP_NAME)) { const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (cclauses == NULL && strcmp (p, "master") == 0) + if (cclauses == NULL && strcmp (p, "masked") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + cclauses = cclauses_buf; + + c_parser_consume_token (parser); + if (!flag_openmp) /* flag_openmp_simd */ + return c_parser_omp_masked (loc, parser, p_name, mask, cclauses, + if_p); + block = c_begin_omp_parallel (); + tree ret = c_parser_omp_masked (loc, parser, p_name, mask, cclauses, + if_p); + stmt = c_finish_omp_parallel (loc, + cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], + block); + if (ret == NULL) + return ret; + /* masked does have just filter clause, but during gimplification + isn't represented by a gimplification omp context, so for + #pragma omp parallel masked don't set OMP_PARALLEL_COMBINED, + so that + #pragma omp parallel masked + #pragma omp taskloop simd lastprivate (x) + isn't confused with + #pragma omp parallel masked taskloop simd lastprivate (x) */ + if (OMP_MASKED_COMBINED (ret)) + OMP_PARALLEL_COMBINED (stmt) = 1; + return stmt; + } + else if (cclauses == NULL && strcmp (p, "master") == 0) { tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; cclauses = cclauses_buf; @@ -19126,7 +19907,16 @@ c_parser_omp_parallel (location_t loc, c_parser *parser, block); if (ret == NULL) return ret; - OMP_PARALLEL_COMBINED (stmt) = 1; + /* master doesn't have any clauses and during gimplification + isn't represented by a gimplification omp context, so for + #pragma omp parallel master don't set OMP_PARALLEL_COMBINED, + so that + #pragma omp parallel master + #pragma omp taskloop simd lastprivate (x) + isn't confused with + #pragma omp parallel master taskloop simd lastprivate (x) */ + if (OMP_MASTER_COMBINED (ret)) + OMP_PARALLEL_COMBINED (stmt) = 1; return stmt; } else if (strcmp (p, "loop") == 0) @@ -19220,6 +20010,33 @@ c_parser_omp_single (location_t loc, c_parser *parser, bool *if_p) return add_stmt (stmt); } +/* OpenMP 5.1: + # pragma omp scope scope-clause[optseq] new-line + structured-block + + LOC is the location of the #pragma. +*/ + +#define OMP_SCOPE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static tree +c_parser_omp_scope (location_t loc, c_parser *parser, bool *if_p) +{ + tree stmt = make_node (OMP_SCOPE); + SET_EXPR_LOCATION (stmt, loc); + TREE_TYPE (stmt) = void_type_node; + + OMP_SCOPE_CLAUSES (stmt) + = c_parser_omp_all_clauses (parser, OMP_SCOPE_CLAUSE_MASK, + "#pragma omp scope"); + OMP_SCOPE_BODY (stmt) = c_parser_omp_structured_block (parser, if_p); + + return add_stmt (stmt); +} + /* OpenMP 3.0: # pragma omp task task-clause[optseq] new-line @@ -19239,7 +20056,8 @@ c_parser_omp_single (location_t loc, c_parser *parser, bool *if_p) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DETACH)) + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DETACH) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_AFFINITY)) static tree c_parser_omp_task (location_t loc, c_parser *parser, bool *if_p) @@ -19359,7 +20177,7 @@ c_parser_omp_cancel (c_parser *parser) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP)) -static void +static bool c_parser_omp_cancellation_point (c_parser *parser, enum pragma_context context) { location_t loc = c_parser_peek_token (parser)->location; @@ -19380,7 +20198,7 @@ c_parser_omp_cancellation_point (c_parser *parser, enum pragma_context context) { c_parser_error (parser, "expected %<point%>"); c_parser_skip_to_pragma_eol (parser); - return; + return false; } if (context != pragma_compound) @@ -19392,7 +20210,7 @@ c_parser_omp_cancellation_point (c_parser *parser, enum pragma_context context) else c_parser_error (parser, "expected declaration specifiers"); c_parser_skip_to_pragma_eol (parser, false); - return; + return true; } clauses @@ -19400,6 +20218,7 @@ c_parser_omp_cancellation_point (c_parser *parser, enum pragma_context context) "#pragma omp cancellation point"); c_finish_omp_cancellation_point (loc, clauses); + return true; } /* OpenMP 4.0: @@ -19685,7 +20504,7 @@ c_parser_omp_target_update (location_t loc, c_parser *parser, error_at (loc, "%<#pragma %s%> may only be used in compound statements", "omp target update"); c_parser_skip_to_pragma_eol (parser, false); - return false; + return true; } tree clauses @@ -19718,7 +20537,7 @@ c_parser_omp_target_update (location_t loc, c_parser *parser, | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) -static tree +static bool c_parser_omp_target_enter_data (location_t loc, c_parser *parser, enum pragma_context context) { @@ -19736,7 +20555,7 @@ c_parser_omp_target_enter_data (location_t loc, c_parser *parser, { c_parser_error (parser, "expected %<data%>"); c_parser_skip_to_pragma_eol (parser); - return NULL_TREE; + return false; } if (context == pragma_stmt) @@ -19744,7 +20563,7 @@ c_parser_omp_target_enter_data (location_t loc, c_parser *parser, error_at (loc, "%<#pragma %s%> may only be used in compound statements", "omp target enter data"); c_parser_skip_to_pragma_eol (parser, false); - return NULL_TREE; + return true; } tree clauses @@ -19783,7 +20602,7 @@ c_parser_omp_target_enter_data (location_t loc, c_parser *parser, error_at (loc, "%<#pragma omp target enter data%> must contain at least " "one %<map%> clause"); - return NULL_TREE; + return true; } tree stmt = make_node (OMP_TARGET_ENTER_DATA); @@ -19791,7 +20610,7 @@ c_parser_omp_target_enter_data (location_t loc, c_parser *parser, OMP_TARGET_ENTER_DATA_CLAUSES (stmt) = clauses; SET_EXPR_LOCATION (stmt, loc); add_stmt (stmt); - return stmt; + return true; } /* OpenMP 4.5: @@ -19804,7 +20623,7 @@ c_parser_omp_target_enter_data (location_t loc, c_parser *parser, | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) -static tree +static bool c_parser_omp_target_exit_data (location_t loc, c_parser *parser, enum pragma_context context) { @@ -19822,7 +20641,7 @@ c_parser_omp_target_exit_data (location_t loc, c_parser *parser, { c_parser_error (parser, "expected %<data%>"); c_parser_skip_to_pragma_eol (parser); - return NULL_TREE; + return false; } if (context == pragma_stmt) @@ -19830,7 +20649,7 @@ c_parser_omp_target_exit_data (location_t loc, c_parser *parser, error_at (loc, "%<#pragma %s%> may only be used in compound statements", "omp target exit data"); c_parser_skip_to_pragma_eol (parser, false); - return NULL_TREE; + return true; } tree clauses @@ -19871,7 +20690,7 @@ c_parser_omp_target_exit_data (location_t loc, c_parser *parser, error_at (loc, "%<#pragma omp target exit data%> must contain at least one " "%<map%> clause"); - return NULL_TREE; + return true; } tree stmt = make_node (OMP_TARGET_EXIT_DATA); @@ -19879,7 +20698,7 @@ c_parser_omp_target_exit_data (location_t loc, c_parser *parser, OMP_TARGET_EXIT_DATA_CLAUSES (stmt) = clauses; SET_EXPR_LOCATION (stmt, loc); add_stmt (stmt); - return stmt; + return true; } /* OpenMP 4.0: @@ -19896,6 +20715,7 @@ c_parser_omp_target_exit_data (location_t loc, c_parser *parser, | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULTMAP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR)) static bool @@ -20014,6 +20834,7 @@ c_parser_omp_target (c_parser *parser, enum pragma_context context, bool *if_p) tree stmt = make_node (OMP_TARGET); TREE_TYPE (stmt) = void_type_node; OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET]; + c_omp_adjust_map_clauses (OMP_TARGET_CLAUSES (stmt), true); OMP_TARGET_BODY (stmt) = block; OMP_TARGET_COMBINED (stmt) = 1; SET_EXPR_LOCATION (stmt, loc); @@ -20035,14 +20856,12 @@ c_parser_omp_target (c_parser *parser, enum pragma_context context, bool *if_p) else if (strcmp (p, "enter") == 0) { c_parser_consume_token (parser); - c_parser_omp_target_enter_data (loc, parser, context); - return false; + return c_parser_omp_target_enter_data (loc, parser, context); } else if (strcmp (p, "exit") == 0) { c_parser_consume_token (parser); - c_parser_omp_target_exit_data (loc, parser, context); - return false; + return c_parser_omp_target_exit_data (loc, parser, context); } else if (strcmp (p, "update") == 0) { @@ -20061,7 +20880,18 @@ c_parser_omp_target (c_parser *parser, enum pragma_context context, bool *if_p) OMP_TARGET_CLAUSES (stmt) = c_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK, - "#pragma omp target"); + "#pragma omp target", false); + for (tree c = OMP_TARGET_CLAUSES (stmt); c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION) + { + tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); + OMP_CLAUSE_DECL (nc) = OMP_CLAUSE_DECL (c); + OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_ALWAYS_TOFROM); + OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c); + OMP_CLAUSE_CHAIN (c) = nc; + } + OMP_TARGET_CLAUSES (stmt) + = c_finish_omp_clauses (OMP_TARGET_CLAUSES (stmt), C_ORT_OMP_TARGET); c_omp_adjust_map_clauses (OMP_TARGET_CLAUSES (stmt), true); pc = &OMP_TARGET_CLAUSES (stmt); @@ -20190,12 +21020,12 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context) while (c_parser_next_token_is (parser, CPP_KEYWORD) && c_parser_peek_token (parser)->keyword == RID_EXTENSION); c_parser_declaration_or_fndef (parser, true, true, true, false, true, - NULL, clauses); + NULL, &clauses); restore_extension_diagnostics (ext); } else c_parser_declaration_or_fndef (parser, true, true, true, false, true, - NULL, clauses); + NULL, &clauses); break; case pragma_struct: case pragma_param: @@ -20216,7 +21046,7 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context) if (c_parser_next_tokens_start_declaration (parser)) { c_parser_declaration_or_fndef (parser, true, true, true, true, - true, NULL, clauses); + true, NULL, &clauses); restore_extension_diagnostics (ext); break; } @@ -20225,7 +21055,7 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context) else if (c_parser_next_tokens_start_declaration (parser)) { c_parser_declaration_or_fndef (parser, true, true, true, true, true, - NULL, clauses); + NULL, &clauses); break; } error ("%<#pragma omp declare %s%> must be followed by " @@ -20706,8 +21536,10 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms) static void c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms, - vec<c_token> clauses) + vec<c_token> *pclauses) { + vec<c_token> &clauses = *pclauses; + /* Normally first token is CPP_NAME "simd" or "variant". CPP_EOF there indicates error has been reported and CPP_PRAGMA that c_finish_omp_declare_simd has already processed the tokens. */ @@ -21288,7 +22120,7 @@ c_parser_omp_declare_reduction (c_parser *parser, enum pragma_context context) OpenMP 5.0 #pragma omp declare variant (identifier) match (context-selector) */ -static void +static bool c_parser_omp_declare (c_parser *parser, enum pragma_context context) { c_parser_consume_pragma (parser); @@ -21300,37 +22132,38 @@ c_parser_omp_declare (c_parser *parser, enum pragma_context context) /* c_parser_consume_token (parser); done in c_parser_omp_declare_simd. */ c_parser_omp_declare_simd (parser, context); - return; + return true; } if (strcmp (p, "reduction") == 0) { c_parser_consume_token (parser); c_parser_omp_declare_reduction (parser, context); - return; + return false; } if (!flag_openmp) /* flag_openmp_simd */ { c_parser_skip_to_pragma_eol (parser, false); - return; + return false; } if (strcmp (p, "target") == 0) { c_parser_consume_token (parser); c_parser_omp_declare_target (parser); - return; + return false; } if (strcmp (p, "variant") == 0) { /* c_parser_consume_token (parser); done in c_parser_omp_declare_simd. */ c_parser_omp_declare_simd (parser, context); - return; + return true; } } c_parser_error (parser, "expected %<simd%>, %<reduction%>, " "%<target%> or %<variant%>"); c_parser_skip_to_pragma_eol (parser); + return false; } /* OpenMP 5.0 @@ -21347,7 +22180,9 @@ c_parser_omp_requires (c_parser *parser) location_t loc = c_parser_peek_token (parser)->location; while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) { - if (!first && c_parser_next_token_is (parser, CPP_COMMA)) + if (!first + && c_parser_next_token_is (parser, CPP_COMMA) + && c_parser_peek_2nd_token (parser)->type == CPP_NAME) c_parser_consume_token (parser); first = false; @@ -21394,9 +22229,18 @@ c_parser_omp_requires (c_parser *parser) error_at (c_parser_peek_token (parser)->location, "expected %<seq_cst%>, %<relaxed%> or " "%<acq_rel%>"); - if (c_parser_peek_2nd_token (parser)->type - == CPP_CLOSE_PAREN) - c_parser_consume_token (parser); + switch (c_parser_peek_token (parser)->type) + { + case CPP_EOF: + case CPP_PRAGMA_EOL: + case CPP_CLOSE_PAREN: + break; + default: + if (c_parser_peek_2nd_token (parser)->type + == CPP_CLOSE_PAREN) + c_parser_consume_token (parser); + break; + } } else c_parser_consume_token (parser); @@ -21597,6 +22441,183 @@ c_parser_omp_taskloop (location_t loc, c_parser *parser, return ret; } +/* OpenMP 5.1 + #pragma omp nothing new-line */ + +static void +c_parser_omp_nothing (c_parser *parser) +{ + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser); +} + +/* OpenMP 5.1 + #pragma omp error clauses[optseq] new-line */ + +static bool +c_parser_omp_error (c_parser *parser, enum pragma_context context) +{ + int at_compilation = -1; + int severity_fatal = -1; + tree message = NULL_TREE; + bool first = true; + bool bad = false; + location_t loc = c_parser_peek_token (parser)->location; + + c_parser_consume_pragma (parser); + + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + { + if (!first + && c_parser_next_token_is (parser, CPP_COMMA) + && c_parser_peek_2nd_token (parser)->type == CPP_NAME) + c_parser_consume_token (parser); + + first = false; + + if (!c_parser_next_token_is (parser, CPP_NAME)) + break; + + const char *p + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + location_t cloc = c_parser_peek_token (parser)->location; + static const char *args[] = { + "execution", "compilation", "warning", "fatal" + }; + int *v = NULL; + int idx = 0, n = -1; + tree m = NULL_TREE; + + if (!strcmp (p, "at")) + v = &at_compilation; + else if (!strcmp (p, "severity")) + { + v = &severity_fatal; + idx += 2; + } + else if (strcmp (p, "message")) + { + error_at (cloc, + "expected %<at%>, %<severity%> or %<message%> clause"); + c_parser_skip_to_pragma_eol (parser, false); + return false; + } + + c_parser_consume_token (parser); + + matching_parens parens; + if (parens.require_open (parser)) + { + if (v == NULL) + { + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, true, true); + m = convert (const_string_type_node, expr.value); + m = c_fully_fold (m, false, NULL); + } + else + { + if (c_parser_next_token_is (parser, CPP_NAME)) + { + tree val = c_parser_peek_token (parser)->value; + const char *q = IDENTIFIER_POINTER (val); + + if (!strcmp (q, args[idx])) + n = 0; + else if (!strcmp (q, args[idx + 1])) + n = 1; + } + if (n == -1) + { + error_at (c_parser_peek_token (parser)->location, + "expected %qs or %qs", args[idx], args[idx + 1]); + bad = true; + switch (c_parser_peek_token (parser)->type) + { + case CPP_EOF: + case CPP_PRAGMA_EOL: + case CPP_CLOSE_PAREN: + break; + default: + if (c_parser_peek_2nd_token (parser)->type + == CPP_CLOSE_PAREN) + c_parser_consume_token (parser); + break; + } + } + else + c_parser_consume_token (parser); + } + + parens.skip_until_found_close (parser); + + if (v == NULL) + { + if (message) + { + error_at (cloc, "too many %qs clauses", p); + bad = true; + } + else + message = m; + } + else if (n != -1) + { + if (*v != -1) + { + error_at (cloc, "too many %qs clauses", p); + bad = true; + } + else + *v = n; + } + } + else + bad = true; + } + c_parser_skip_to_pragma_eol (parser); + if (bad) + return true; + + if (at_compilation == -1) + at_compilation = 1; + if (severity_fatal == -1) + severity_fatal = 1; + if (!at_compilation) + { + if (context != pragma_compound) + { + error_at (loc, "%<#pragma omp error%> with %<at(execution)%> clause " + "may only be used in compound statements"); + return true; + } + tree fndecl + = builtin_decl_explicit (severity_fatal ? BUILT_IN_GOMP_ERROR + : BUILT_IN_GOMP_WARNING); + if (!message) + message = build_zero_cst (const_string_type_node); + tree stmt = build_call_expr_loc (loc, fndecl, 2, message, + build_all_ones_cst (size_type_node)); + add_stmt (stmt); + return true; + } + const char *msg = NULL; + if (message) + { + msg = c_getstr (message); + if (msg == NULL) + msg = _("<message unknown at compile time>"); + } + if (msg) + emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, + "%<pragma omp error%> encountered: %s", msg); + else + emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, + "%<pragma omp error%> encountered"); + return false; +} + /* Main entry point to parsing most OpenMP pragmas. */ static void @@ -21662,6 +22683,10 @@ c_parser_omp_construct (c_parser *parser, bool *if_p) strcpy (p_name, "#pragma omp"); stmt = c_parser_omp_loop (loc, parser, p_name, mask, NULL, if_p); break; + case PRAGMA_OMP_MASKED: + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_masked (loc, parser, p_name, mask, NULL, if_p); + break; case PRAGMA_OMP_MASTER: strcpy (p_name, "#pragma omp"); stmt = c_parser_omp_master (loc, parser, p_name, mask, NULL, if_p); @@ -21670,6 +22695,9 @@ c_parser_omp_construct (c_parser *parser, bool *if_p) strcpy (p_name, "#pragma omp"); stmt = c_parser_omp_parallel (loc, parser, p_name, mask, NULL, if_p); break; + case PRAGMA_OMP_SCOPE: + stmt = c_parser_omp_scope (loc, parser, if_p); + break; case PRAGMA_OMP_SECTIONS: strcpy (p_name, "#pragma omp"); stmt = c_parser_omp_sections (loc, parser, p_name, mask, NULL); diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index a671a3e..d50d0cb 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -370,6 +370,8 @@ struct c_declspecs { BOOL_BITFIELD explicit_signed_p : 1; /* Whether the specifiers include a deprecated typedef. */ BOOL_BITFIELD deprecated_p : 1; + /* Whether the specifiers include an unavailable typedef. */ + BOOL_BITFIELD unavailable_p : 1; /* Whether the type defaulted to "int" because there were no type specifiers. */ BOOL_BITFIELD default_int_p : 1; @@ -595,7 +597,7 @@ extern void finish_function (location_t = input_location); extern tree finish_struct (location_t, tree, tree, tree, class c_struct_parse_info *); extern tree c_simulate_enum_decl (location_t, const char *, - vec<string_int_pair>); + vec<string_int_pair> *); extern struct c_arg_info *build_arg_info (void); extern struct c_arg_info *get_parm_info (bool, tree); extern tree grokfield (location_t, struct c_declarator *, @@ -759,8 +761,9 @@ extern tree c_finish_omp_clauses (tree, enum c_omp_region_type); extern tree c_build_va_arg (location_t, tree, location_t, tree); extern tree c_finish_transaction (location_t, tree, int); extern bool c_tree_equal (tree, tree); -extern tree c_build_function_call_vec (location_t, vec<location_t>, tree, - vec<tree, va_gc> *, vec<tree, va_gc> *); +extern tree c_build_function_call_vec (location_t, const vec<location_t>&, + tree, vec<tree, va_gc> *, + vec<tree, va_gc> *); extern tree c_omp_clause_copy_ctor (tree, tree, tree); /* Set to 0 at beginning of a function definition, set to 1 if diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 4e6d369..49d1bb0 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -740,10 +740,16 @@ c_common_type (tree t1, tree t2) t2 = TYPE_MAIN_VARIANT (t2); if (TYPE_ATTRIBUTES (t1) != NULL_TREE) - t1 = build_type_attribute_variant (t1, NULL_TREE); + { + tree attrs = affects_type_identity_attributes (TYPE_ATTRIBUTES (t1)); + t1 = build_type_attribute_variant (t1, attrs); + } if (TYPE_ATTRIBUTES (t2) != NULL_TREE) - t2 = build_type_attribute_variant (t2, NULL_TREE); + { + tree attrs = affects_type_identity_attributes (TYPE_ATTRIBUTES (t2)); + t2 = build_type_attribute_variant (t2, attrs); + } /* Save time if the two types are the same. */ @@ -1322,8 +1328,8 @@ comp_target_types (location_t location, tree ttl, tree ttr) val = comptypes_check_enum_int (mvl, mvr, &enum_and_int_p); if (val == 1 && val_ped != 1) - pedwarn (location, OPT_Wpedantic, "pointers to arrays with different qualifiers " - "are incompatible in ISO C"); + pedwarn_c11 (location, OPT_Wpedantic, "invalid use of pointers to arrays with different qualifiers " + "in ISO C before C2X"); if (val == 2) pedwarn (location, OPT_Wpedantic, "types are not quite compatible"); @@ -1686,7 +1692,7 @@ function_types_compatible_p (const_tree f1, const_tree f2, if (args1 == NULL_TREE) { - if (!self_promoting_args_p (args2)) + if (flag_isoc2x ? stdarg_p (f2) : !self_promoting_args_p (args2)) return 0; /* If one of these types comes from a non-prototype fn definition, compare that with the other type's arglist. @@ -1699,7 +1705,7 @@ function_types_compatible_p (const_tree f1, const_tree f2, } if (args2 == NULL_TREE) { - if (!self_promoting_args_p (args1)) + if (flag_isoc2x ? stdarg_p (f1) : !self_promoting_args_p (args1)) return 0; if (TYPE_ACTUAL_ARG_TYPES (f2) && type_lists_compatible_p (args1, TYPE_ACTUAL_ARG_TYPES (f2), @@ -1905,8 +1911,7 @@ array_to_pointer_conversion (location_t loc, tree exp) STRIP_TYPE_NOPS (exp); - if (TREE_NO_WARNING (orig_exp)) - TREE_NO_WARNING (exp) = 1; + copy_warning (exp, orig_exp); ptrtype = build_pointer_type (restype); @@ -1939,8 +1944,7 @@ function_to_pointer_conversion (location_t loc, tree exp) STRIP_TYPE_NOPS (exp); - if (TREE_NO_WARNING (orig_exp)) - TREE_NO_WARNING (exp) = 1; + copy_warning (exp, orig_exp); return build_unary_op (loc, ADDR_EXPR, exp, false); } @@ -1968,6 +1972,50 @@ mark_exp_read (tree exp) mark_exp_read (TREE_OPERAND (exp, 0)); break; case COMPOUND_EXPR: + /* Pattern match what build_atomic_assign produces with modifycode + NOP_EXPR. */ + if (VAR_P (TREE_OPERAND (exp, 1)) + && DECL_ARTIFICIAL (TREE_OPERAND (exp, 1)) + && TREE_CODE (TREE_OPERAND (exp, 0)) == COMPOUND_EXPR) + { + tree t1 = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); + tree t2 = TREE_OPERAND (TREE_OPERAND (exp, 0), 1); + if (TREE_CODE (t1) == TARGET_EXPR + && TARGET_EXPR_SLOT (t1) == TREE_OPERAND (exp, 1) + && TREE_CODE (t2) == CALL_EXPR) + { + tree fndecl = get_callee_fndecl (t2); + tree arg = NULL_TREE; + if (fndecl + && TREE_CODE (fndecl) == FUNCTION_DECL + && fndecl_built_in_p (fndecl, BUILT_IN_NORMAL) + && call_expr_nargs (t2) >= 2) + switch (DECL_FUNCTION_CODE (fndecl)) + { + case BUILT_IN_ATOMIC_STORE: + arg = CALL_EXPR_ARG (t2, 1); + break; + case BUILT_IN_ATOMIC_STORE_1: + case BUILT_IN_ATOMIC_STORE_2: + case BUILT_IN_ATOMIC_STORE_4: + case BUILT_IN_ATOMIC_STORE_8: + case BUILT_IN_ATOMIC_STORE_16: + arg = CALL_EXPR_ARG (t2, 0); + break; + default: + break; + } + if (arg) + { + STRIP_NOPS (arg); + if (TREE_CODE (arg) == ADDR_EXPR + && DECL_P (TREE_OPERAND (arg, 0)) + && TYPE_ATOMIC (TREE_TYPE (TREE_OPERAND (arg, 0)))) + mark_exp_read (TREE_OPERAND (arg, 0)); + } + } + } + /* FALLTHRU */ case C_MAYBE_CONST_EXPR: mark_exp_read (TREE_OPERAND (exp, 1)); break; @@ -2005,8 +2053,7 @@ default_function_array_conversion (location_t loc, struct c_expr exp) exp.value = TREE_OPERAND (exp.value, 0); } - if (TREE_NO_WARNING (orig_exp)) - TREE_NO_WARNING (exp.value) = 1; + copy_warning (exp.value, orig_exp); lvalue_array_p = !not_lvalue && lvalue_p (exp.value); if (!flag_isoc99 && !lvalue_array_p) @@ -2104,7 +2151,8 @@ convert_lvalue_to_rvalue (location_t loc, struct c_expr exp, tmp = create_tmp_var_raw (nonatomic_type); tmp_addr = build_unary_op (loc, ADDR_EXPR, tmp, false); TREE_ADDRESSABLE (tmp) = 1; - TREE_NO_WARNING (tmp) = 1; + /* Do not disable warnings for TMP even though it's artificial. + -Winvalid-memory-model depends on it. */ /* Issue __atomic_load (&expr, &tmp, SEQ_CST); */ fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_LOAD); @@ -2201,8 +2249,7 @@ default_conversion (tree exp) orig_exp = exp; STRIP_TYPE_NOPS (exp); - if (TREE_NO_WARNING (orig_exp)) - TREE_NO_WARNING (exp) = 1; + copy_warning (exp, orig_exp); if (code == VOID_TYPE) { @@ -2511,7 +2558,9 @@ build_component_ref (location_t loc, tree datum, tree component, || (use_datum_quals && TREE_THIS_VOLATILE (datum))) TREE_THIS_VOLATILE (ref) = 1; - if (TREE_DEPRECATED (subdatum)) + if (TREE_UNAVAILABLE (subdatum)) + error_unavailable_use (subdatum, NULL_TREE); + else if (TREE_DEPRECATED (subdatum)) warn_deprecated_use (subdatum, NULL_TREE); datum = ref; @@ -2566,7 +2615,7 @@ build_indirect_ref (location_t loc, tree ptr, ref_operator errstring) if (warn_strict_aliasing > 2) if (strict_aliasing_warning (EXPR_LOCATION (pointer), type, TREE_OPERAND (pointer, 0))) - TREE_NO_WARNING (pointer) = 1; + suppress_warning (pointer, OPT_Wstrict_aliasing_); } if (TREE_CODE (pointer) == ADDR_EXPR @@ -2796,7 +2845,9 @@ build_external_ref (location_t loc, tree id, bool fun, tree *type) if (TREE_TYPE (ref) == error_mark_node) return error_mark_node; - if (TREE_DEPRECATED (ref)) + if (TREE_UNAVAILABLE (ref)) + error_unavailable_use (ref, NULL_TREE); + else if (TREE_DEPRECATED (ref)) warn_deprecated_use (ref, NULL_TREE); /* Recursive call does not count as usage. */ @@ -2945,7 +2996,7 @@ c_expr_sizeof_expr (location_t loc, struct c_expr expr) c_last_sizeof_loc = loc; ret.original_code = SIZEOF_EXPR; ret.original_type = NULL; - if (c_vla_type_p (TREE_TYPE (folded_expr))) + if (C_TYPE_VARIABLE_SIZE (TREE_TYPE (folded_expr))) { /* sizeof is evaluated when given a vla (C99 6.5.3.4p2). */ ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value), @@ -2975,8 +3026,14 @@ c_expr_sizeof_type (location_t loc, struct c_type_name *t) c_last_sizeof_loc = loc; ret.original_code = SIZEOF_EXPR; ret.original_type = NULL; + if (type == error_mark_node) + { + ret.value = error_mark_node; + ret.original_code = ERROR_MARK; + } + else if ((type_expr || TREE_CODE (ret.value) == INTEGER_CST) - && c_vla_type_p (type)) + && C_TYPE_VARIABLE_SIZE (type)) { /* If the type is a [*] array, it is a VLA but is represented as having a size of zero. In such a case we must ensure that @@ -3063,7 +3120,7 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc, orig_fundecl = fundecl; /* Atomic functions have type checking/casting already done. They are often rewritten and don't match the original parameter list. */ - if (name && !strncmp (IDENTIFIER_POINTER (name), "__atomic_", 9)) + if (name && startswith (IDENTIFIER_POINTER (name), "__atomic_")) origtypes = NULL; } if (TREE_CODE (TREE_TYPE (function)) == FUNCTION_TYPE) @@ -3149,7 +3206,7 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc, nargs, argarray, &arg_loc); if (name != NULL_TREE - && !strncmp (IDENTIFIER_POINTER (name), "__builtin_", 10)) + && startswith (IDENTIFIER_POINTER (name), "__builtin_")) { if (require_constant_value) result @@ -3168,7 +3225,7 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc, /* If -Wnonnull warning has been diagnosed, avoid diagnosing it again later. */ if (warned_p && TREE_CODE (result) == CALL_EXPR) - TREE_NO_WARNING (result) = 1; + suppress_warning (result, OPT_Wnonnull); /* In this improbable scenario, a nested function returns a VM type. Create a TARGET_EXPR so that the call always has a LHS, much as @@ -3193,7 +3250,7 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc, /* Like build_function_call_vec, but call also resolve_overloaded_builtin. */ tree -c_build_function_call_vec (location_t loc, vec<location_t> arg_loc, +c_build_function_call_vec (location_t loc, const vec<location_t> &arg_loc, tree function, vec<tree, va_gc> *params, vec<tree, va_gc> *origtypes) { @@ -4065,7 +4122,7 @@ build_atomic_assign (location_t loc, tree lhs, enum tree_code modifycode, vec<tree, va_gc> *params; tree val, nonatomic_lhs_type, nonatomic_rhs_type, newval, newval_addr; tree old, old_addr; - tree compound_stmt; + tree compound_stmt = NULL_TREE; tree stmt, goto_stmt; tree loop_label, loop_decl, done_label, done_decl; @@ -4086,7 +4143,15 @@ build_atomic_assign (location_t loc, tree lhs, enum tree_code modifycode, /* Create a compound statement to hold the sequence of statements with a loop. */ - compound_stmt = c_begin_compound_stmt (false); + if (modifycode != NOP_EXPR) + { + compound_stmt = c_begin_compound_stmt (false); + + /* For consistency with build_modify_expr on non-_Atomic, + mark the lhs as read. Also, it would be very hard to match + such expressions in mark_exp_read. */ + mark_exp_read (lhs); + } /* Remove any excess precision (which is only present here in the case of compound assignments). */ @@ -4109,16 +4174,19 @@ build_atomic_assign (location_t loc, tree lhs, enum tree_code modifycode, TYPE_UNQUALIFIED); val = create_tmp_var_raw (nonatomic_rhs_type); TREE_ADDRESSABLE (val) = 1; - TREE_NO_WARNING (val) = 1; + suppress_warning (val); rhs = build4 (TARGET_EXPR, nonatomic_rhs_type, val, rhs, NULL_TREE, NULL_TREE); + TREE_SIDE_EFFECTS (rhs) = 1; SET_EXPR_LOCATION (rhs, loc); - add_stmt (rhs); + if (modifycode != NOP_EXPR) + add_stmt (rhs); /* NOP_EXPR indicates it's a straight store of the RHS. Simply issue an atomic_store. */ if (modifycode == NOP_EXPR) { + compound_stmt = rhs; /* Build __atomic_store (&lhs, &val, SEQ_CST) */ rhs = build_unary_op (loc, ADDR_EXPR, val, false); fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_STORE); @@ -4126,10 +4194,9 @@ build_atomic_assign (location_t loc, tree lhs, enum tree_code modifycode, params->quick_push (rhs); params->quick_push (seq_cst); func_call = c_build_function_call_vec (loc, vNULL, fndecl, params, NULL); - add_stmt (func_call); - /* Finish the compound statement. */ - compound_stmt = c_end_compound_stmt (loc, compound_stmt, false); + compound_stmt = build2 (COMPOUND_EXPR, void_type_node, + compound_stmt, func_call); /* VAL is the value which was stored, return a COMPOUND_STMT of the statement and that value. */ @@ -4208,7 +4275,7 @@ build_atomic_assign (location_t loc, tree lhs, enum tree_code modifycode, newval = create_tmp_var_raw (nonatomic_lhs_type); TREE_ADDRESSABLE (newval) = 1; - TREE_NO_WARNING (newval) = 1; + suppress_warning (newval); rhs = build4 (TARGET_EXPR, nonatomic_lhs_type, newval, func_call, NULL_TREE, NULL_TREE); SET_EXPR_LOCATION (rhs, loc); @@ -4227,12 +4294,12 @@ cas_loop: old = create_tmp_var_raw (nonatomic_lhs_type); old_addr = build_unary_op (loc, ADDR_EXPR, old, false); TREE_ADDRESSABLE (old) = 1; - TREE_NO_WARNING (old) = 1; + suppress_warning (old); newval = create_tmp_var_raw (nonatomic_lhs_type); newval_addr = build_unary_op (loc, ADDR_EXPR, newval, false); TREE_ADDRESSABLE (newval) = 1; - TREE_NO_WARNING (newval) = 1; + suppress_warning (newval); loop_decl = create_artificial_label (loc); loop_label = build1 (LABEL_EXPR, void_type_node, loop_decl); @@ -4721,8 +4788,6 @@ build_unary_op (location_t location, enum tree_code code, tree xarg, else val = build2 (code, TREE_TYPE (arg), arg, inc); TREE_SIDE_EFFECTS (val) = 1; - if (TREE_CODE (val) != code) - TREE_NO_WARNING (val) = 1; ret = val; goto return_build_unary_op; } @@ -4806,6 +4871,7 @@ build_unary_op (location_t location, enum tree_code code, tree xarg, if (TYPE_REVERSE_STORAGE_ORDER (TREE_TYPE (TREE_OPERAND (arg, 0)))) { if (!AGGREGATE_TYPE_P (TREE_TYPE (arg)) + && !POINTER_TYPE_P (TREE_TYPE (arg)) && !VECTOR_TYPE_P (TREE_TYPE (arg))) { error_at (location, "cannot take address of scalar with " @@ -4973,8 +5039,17 @@ c_mark_addressable (tree exp, bool array_ref_p) && TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (x, 0)))) return true; - /* FALLTHRU */ + x = TREE_OPERAND (x, 0); + break; + case COMPONENT_REF: + if (DECL_C_BIT_FIELD (TREE_OPERAND (x, 1))) + { + error ("cannot take address of bit-field %qD", + TREE_OPERAND (x, 1)); + return false; + } + /* FALLTHRU */ case ADDR_EXPR: case ARRAY_REF: case REALPART_EXPR: @@ -5335,39 +5410,41 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, "used in conditional expression"); return error_mark_node; } - else if (VOID_TYPE_P (TREE_TYPE (type1)) - && !TYPE_ATOMIC (TREE_TYPE (type1))) - { - if ((TREE_CODE (TREE_TYPE (type2)) == ARRAY_TYPE) - && (TYPE_QUALS (strip_array_types (TREE_TYPE (type2))) - & ~TYPE_QUALS (TREE_TYPE (type1)))) - warning_at (colon_loc, OPT_Wdiscarded_array_qualifiers, - "pointer to array loses qualifier " - "in conditional expression"); - - if (TREE_CODE (TREE_TYPE (type2)) == FUNCTION_TYPE) + else if ((VOID_TYPE_P (TREE_TYPE (type1)) + && !TYPE_ATOMIC (TREE_TYPE (type1))) + || (VOID_TYPE_P (TREE_TYPE (type2)) + && !TYPE_ATOMIC (TREE_TYPE (type2)))) + { + tree t1 = TREE_TYPE (type1); + tree t2 = TREE_TYPE (type2); + if (!(VOID_TYPE_P (t1) + && !TYPE_ATOMIC (t1))) + { + /* roles are swapped */ + t1 = t2; + t2 = TREE_TYPE (type1); + } + tree t2_stripped = strip_array_types (t2); + if ((TREE_CODE (t2) == ARRAY_TYPE) + && (TYPE_QUALS (t2_stripped) & ~TYPE_QUALS (t1))) + { + if (!flag_isoc2x) + warning_at (colon_loc, OPT_Wdiscarded_array_qualifiers, + "pointer to array loses qualifier " + "in conditional expression"); + else if (warn_c11_c2x_compat > 0) + warning_at (colon_loc, OPT_Wc11_c2x_compat, + "pointer to array loses qualifier " + "in conditional expression in ISO C before C2X"); + } + if (TREE_CODE (t2) == FUNCTION_TYPE) pedwarn (colon_loc, OPT_Wpedantic, "ISO C forbids conditional expr between " "%<void *%> and function pointer"); - result_type = build_pointer_type (qualify_type (TREE_TYPE (type1), - TREE_TYPE (type2))); - } - else if (VOID_TYPE_P (TREE_TYPE (type2)) - && !TYPE_ATOMIC (TREE_TYPE (type2))) - { - if ((TREE_CODE (TREE_TYPE (type1)) == ARRAY_TYPE) - && (TYPE_QUALS (strip_array_types (TREE_TYPE (type1))) - & ~TYPE_QUALS (TREE_TYPE (type2)))) - warning_at (colon_loc, OPT_Wdiscarded_array_qualifiers, - "pointer to array loses qualifier " - "in conditional expression"); - - if (TREE_CODE (TREE_TYPE (type1)) == FUNCTION_TYPE) - pedwarn (colon_loc, OPT_Wpedantic, - "ISO C forbids conditional expr between " - "%<void *%> and function pointer"); - result_type = build_pointer_type (qualify_type (TREE_TYPE (type2), - TREE_TYPE (type1))); + /* for array, use qualifiers of element type */ + if (flag_isoc2x) + t2 = t2_stripped; + result_type = build_pointer_type (qualify_type (t1, t2)); } /* Objective-C pointer comparisons are a bit more lenient. */ else if (objc_have_common_type (type1, type2, -3, NULL_TREE)) @@ -5490,7 +5567,7 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, warn here, because the COND_EXPR will be turned into OP1. */ if (warn_duplicated_branches && TREE_CODE (ret) == COND_EXPR - && (op1 == op2 || operand_equal_p (op1, op2, 0))) + && (op1 == op2 || operand_equal_p (op1, op2, OEP_ADDRESS_OF_SAME_FIELD))) warning_at (EXPR_LOCATION (ret), OPT_Wduplicated_branches, "this condition has identical branches"); @@ -6061,6 +6138,7 @@ build_c_cast (location_t loc, tree type, tree expr) return value reflects this. */ if (int_operands && INTEGRAL_TYPE_P (type) + && value != error_mark_node && !EXPR_INT_CONST_OPERANDS (value)) value = note_integer_operands (value); @@ -6725,27 +6803,40 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, /* This macro is used to emit diagnostics to ensure that all format strings are complete sentences, visible to gettext and checked at - compile time. It is the same as PEDWARN_FOR_ASSIGNMENT but with an - extra parameter to enumerate qualifiers. */ -#define PEDWARN_FOR_QUALIFIERS(LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS) \ + compile time. It can be called with 'pedwarn' or 'warning_at'. */ +#define WARNING_FOR_QUALIFIERS(PEDWARN, LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS) \ do { \ switch (errtype) \ { \ case ic_argpass: \ - { \ - auto_diagnostic_group d; \ - if (pedwarn (PLOC, OPT, AR, parmnum, rname, QUALS)) \ - inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype); \ - } \ + { \ + auto_diagnostic_group d; \ + if (PEDWARN) { \ + if (pedwarn (PLOC, OPT, AR, parmnum, rname, QUALS)) \ + inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype); \ + } else { \ + if (warning_at (PLOC, OPT, AR, parmnum, rname, QUALS)) \ + inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype); \ + } \ + } \ break; \ case ic_assign: \ - pedwarn (LOCATION, OPT, AS, QUALS); \ + if (PEDWARN) \ + pedwarn (LOCATION, OPT, AS, QUALS); \ + else \ + warning_at (LOCATION, OPT, AS, QUALS); \ break; \ case ic_init: \ - pedwarn (LOCATION, OPT, IN, QUALS); \ + if (PEDWARN) \ + pedwarn (LOCATION, OPT, IN, QUALS); \ + else \ + warning_at (LOCATION, OPT, IN, QUALS); \ break; \ case ic_return: \ - pedwarn (LOCATION, OPT, RE, QUALS); \ + if (PEDWARN) \ + pedwarn (LOCATION, OPT, RE, QUALS); \ + else \ + warning_at (LOCATION, OPT, RE, QUALS); \ break; \ default: \ gcc_unreachable (); \ @@ -6754,32 +6845,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, /* This macro is used to emit diagnostics to ensure that all format strings are complete sentences, visible to gettext and checked at - compile time. It is the same as PEDWARN_FOR_QUALIFIERS but uses - warning_at instead of pedwarn. */ -#define WARNING_FOR_QUALIFIERS(LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS) \ - do { \ - switch (errtype) \ - { \ - case ic_argpass: \ - { \ - auto_diagnostic_group d; \ - if (warning_at (PLOC, OPT, AR, parmnum, rname, QUALS)) \ - inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype); \ - } \ - break; \ - case ic_assign: \ - warning_at (LOCATION, OPT, AS, QUALS); \ - break; \ - case ic_init: \ - warning_at (LOCATION, OPT, IN, QUALS); \ - break; \ - case ic_return: \ - warning_at (LOCATION, OPT, RE, QUALS); \ - break; \ - default: \ - gcc_unreachable (); \ - } \ - } while (0) + compile time. It is the same as PEDWARN_FOR_ASSIGNMENT but with an + extra parameter to enumerate qualifiers. */ +#define PEDWARN_FOR_QUALIFIERS(LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS) \ + WARNING_FOR_QUALIFIERS (true, LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS) + if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR) rhs = TREE_OPERAND (rhs, 0); @@ -7234,26 +7304,37 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, && (AGGREGATE_TYPE_P (ttl) && TYPE_REVERSE_STORAGE_ORDER (ttl)) != (AGGREGATE_TYPE_P (ttr) && TYPE_REVERSE_STORAGE_ORDER (ttr))) { + tree t; + switch (errtype) { case ic_argpass: /* Do not warn for built-in functions, for example memcpy, since we control how they behave and they can be useful in this area. */ if (TREE_CODE (rname) != FUNCTION_DECL - || !DECL_IS_UNDECLARED_BUILTIN (rname)) + || !fndecl_built_in_p (rname)) warning_at (location, OPT_Wscalar_storage_order, "passing argument %d of %qE from incompatible " "scalar storage order", parmnum, rname); break; case ic_assign: - warning_at (location, OPT_Wscalar_storage_order, - "assignment to %qT from pointer type %qT with " - "incompatible scalar storage order", type, rhstype); + /* Do not warn if the RHS is a call to a function that returns a + pointer that is not an alias. */ + if (TREE_CODE (rhs) != CALL_EXPR + || (t = get_callee_fndecl (rhs)) == NULL_TREE + || !DECL_IS_MALLOC (t)) + warning_at (location, OPT_Wscalar_storage_order, + "assignment to %qT from pointer type %qT with " + "incompatible scalar storage order", type, rhstype); break; case ic_init: - warning_at (location, OPT_Wscalar_storage_order, - "initialization of %qT from pointer type %qT with " - "incompatible scalar storage order", type, rhstype); + /* Likewise. */ + if (TREE_CODE (rhs) != CALL_EXPR + || (t = get_callee_fndecl (rhs)) == NULL_TREE + || !DECL_IS_MALLOC (t)) + warning_at (location, OPT_Wscalar_storage_order, + "initialization of %qT from pointer type %qT with " + "incompatible scalar storage order", type, rhstype); break; case ic_return: warning_at (location, OPT_Wscalar_storage_order, @@ -7287,17 +7368,18 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, if (TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttr) & ~TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttl)) - WARNING_FOR_QUALIFIERS (location, expr_loc, - OPT_Wdiscarded_array_qualifiers, - G_("passing argument %d of %qE discards " + WARNING_FOR_QUALIFIERS (flag_isoc2x, + location, expr_loc, + OPT_Wdiscarded_array_qualifiers, + G_("passing argument %d of %qE discards " "%qv qualifier from pointer target type"), - G_("assignment discards %qv qualifier " + G_("assignment discards %qv qualifier " "from pointer target type"), - G_("initialization discards %qv qualifier " + G_("initialization discards %qv qualifier " "from pointer target type"), - G_("return discards %qv qualifier from " + G_("return discards %qv qualifier from " "pointer target type"), - TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl)); + TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl)); } else if (pedantic && ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE) @@ -7320,28 +7402,31 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, else if (TREE_CODE (ttr) != FUNCTION_TYPE && TREE_CODE (ttl) != FUNCTION_TYPE) { + /* Assignments between atomic and non-atomic objects are OK. */ + bool warn_quals_ped = TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttr) + & ~TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttl); + bool warn_quals = TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttr) + & ~TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (strip_array_types (ttl)); + /* Don't warn about loss of qualifier for conversions from qualified void* to pointers to arrays with corresponding - qualifier on the element type. */ - if (!pedantic) - ttl = strip_array_types (ttl); + qualifier on the element type (except for pedantic before C23). */ + if (warn_quals || (warn_quals_ped && pedantic && !flag_isoc2x)) + PEDWARN_FOR_QUALIFIERS (location, expr_loc, + OPT_Wdiscarded_qualifiers, + G_("passing argument %d of %qE discards " + "%qv qualifier from pointer target type"), + G_("assignment discards %qv qualifier " + "from pointer target type"), + G_("initialization discards %qv qualifier " + "from pointer target type"), + G_("return discards %qv qualifier from " + "pointer target type"), + TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl)); + else if (warn_quals_ped) + pedwarn_c11 (location, OPT_Wc11_c2x_compat, + "array with qualifier on the element is not qualified before C2X"); - /* Assignments between atomic and non-atomic objects are OK. */ - if (TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttr) - & ~TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttl)) - { - PEDWARN_FOR_QUALIFIERS (location, expr_loc, - OPT_Wdiscarded_qualifiers, - G_("passing argument %d of %qE discards " - "%qv qualifier from pointer target type"), - G_("assignment discards %qv qualifier " - "from pointer target type"), - G_("initialization discards %qv qualifier " - "from pointer target type"), - G_("return discards %qv qualifier from " - "pointer target type"), - TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl)); - } /* If this is not a case of ignoring a mismatch in signedness, no warning. */ else if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr) @@ -10880,7 +10965,8 @@ c_finish_return (location_t loc, tree retval, tree origtype) } ret_stmt = build_stmt (loc, RETURN_EXPR, retval); - TREE_NO_WARNING (ret_stmt) |= no_warning; + if (no_warning) + suppress_warning (ret_stmt, OPT_Wreturn_type); return add_stmt (ret_stmt); } @@ -11156,7 +11242,8 @@ emit_side_effect_warnings (location_t loc, tree expr) ; else if (!TREE_SIDE_EFFECTS (expr)) { - if (!VOID_TYPE_P (TREE_TYPE (expr)) && !TREE_NO_WARNING (expr)) + if (!VOID_TYPE_P (TREE_TYPE (expr)) + && !warning_suppressed_p (expr, OPT_Wunused_value)) warning_at (loc, OPT_Wunused_value, "statement with no effect"); } else if (TREE_CODE (expr) == COMPOUND_EXPR) @@ -11172,8 +11259,8 @@ emit_side_effect_warnings (location_t loc, tree expr) if (!TREE_SIDE_EFFECTS (r) && !VOID_TYPE_P (TREE_TYPE (r)) && !CONVERT_EXPR_P (r) - && !TREE_NO_WARNING (r) - && !TREE_NO_WARNING (expr)) + && !warning_suppressed_p (r, OPT_Wunused_value) + && !warning_suppressed_p (expr, OPT_Wunused_value)) warning_at (cloc, OPT_Wunused_value, "right-hand operand of comma expression has no effect"); } @@ -11342,7 +11429,7 @@ c_finish_stmt_expr (location_t loc, tree body) last = c_wrap_maybe_const (last, true); /* Do not warn if the return value of a statement expression is unused. */ - TREE_NO_WARNING (last) = 1; + suppress_warning (last, OPT_Wunused); return last; } @@ -12339,6 +12426,13 @@ build_binary_op (location_t location, enum tree_code code, maybe_warn_bool_compare (location, code, orig_op0, orig_op1); break; + case MIN_EXPR: + case MAX_EXPR: + /* Used for OpenMP atomics. */ + gcc_assert (flag_openmp); + common = 1; + break; + default: gcc_unreachable (); } @@ -13003,7 +13097,8 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, if (error_operand_p (t)) return error_mark_node; ret = t; - if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND && TYPE_ATOMIC (strip_array_types (TREE_TYPE (t)))) { error_at (OMP_CLAUSE_LOCATION (c), "%<_Atomic%> %qE in %qs clause", @@ -13054,14 +13149,16 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); return error_mark_node; } - else if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + else if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND && TYPE_ATOMIC (TREE_TYPE (t))) { error_at (OMP_CLAUSE_LOCATION (c), "%<_Atomic%> %qD in %qs clause", t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); return error_mark_node; } - else if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + else if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND && VAR_P (t) && DECL_THREAD_LOCAL_P (t)) { @@ -13070,7 +13167,8 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); return error_mark_node; } - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND) && TYPE_ATOMIC (TREE_TYPE (t)) && POINTER_TYPE_P (TREE_TYPE (t))) { @@ -13141,7 +13239,8 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, { if (!integer_nonzerop (length)) { - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION) @@ -13209,7 +13308,8 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, } if (tree_int_cst_equal (size, low_bound)) { - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION) @@ -13230,7 +13330,8 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, } else if (length == NULL_TREE) { - if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_IN_REDUCTION && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_TASK_REDUCTION) @@ -13268,7 +13369,8 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, } else if (length == NULL_TREE) { - if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_IN_REDUCTION && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_TASK_REDUCTION) @@ -13313,6 +13415,7 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, /* If there is a pointer type anywhere but in the very first array-section-subscript, the array section can't be contiguous. */ if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY && TREE_CODE (TREE_CHAIN (t)) == TREE_LIST) { error_at (OMP_CLAUSE_LOCATION (c), @@ -13349,7 +13452,8 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) unsigned int first_non_one = 0; auto_vec<tree, 10> types; tree *tp = &OMP_CLAUSE_DECL (c); - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY) && TREE_CODE (*tp) == TREE_LIST && TREE_PURPOSE (*tp) && TREE_CODE (TREE_PURPOSE (*tp)) == TREE_VEC) @@ -13361,7 +13465,8 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) return true; if (first == NULL_TREE) return false; - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY) { tree t = *tp; tree tem = NULL_TREE; @@ -13556,35 +13661,33 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)) return false; gcc_assert (OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_FORCE_DEVICEPTR); - if (ort == C_ORT_OMP || ort == C_ORT_ACC) - switch (OMP_CLAUSE_MAP_KIND (c)) - { - case GOMP_MAP_ALLOC: - case GOMP_MAP_IF_PRESENT: - case GOMP_MAP_TO: - case GOMP_MAP_FROM: - case GOMP_MAP_TOFROM: - case GOMP_MAP_ALWAYS_TO: - case GOMP_MAP_ALWAYS_FROM: - case GOMP_MAP_ALWAYS_TOFROM: - case GOMP_MAP_RELEASE: - case GOMP_MAP_DELETE: - case GOMP_MAP_FORCE_TO: - case GOMP_MAP_FORCE_FROM: - case GOMP_MAP_FORCE_TOFROM: - case GOMP_MAP_FORCE_PRESENT: - OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION (c) = 1; - break; - default: - break; - } + switch (OMP_CLAUSE_MAP_KIND (c)) + { + case GOMP_MAP_ALLOC: + case GOMP_MAP_IF_PRESENT: + case GOMP_MAP_TO: + case GOMP_MAP_FROM: + case GOMP_MAP_TOFROM: + case GOMP_MAP_ALWAYS_TO: + case GOMP_MAP_ALWAYS_FROM: + case GOMP_MAP_ALWAYS_TOFROM: + case GOMP_MAP_RELEASE: + case GOMP_MAP_DELETE: + case GOMP_MAP_FORCE_TO: + case GOMP_MAP_FORCE_FROM: + case GOMP_MAP_FORCE_TOFROM: + case GOMP_MAP_FORCE_PRESENT: + OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION (c) = 1; + break; + default: + break; + } tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); - if (ort != C_ORT_OMP && ort != C_ORT_ACC) - OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_POINTER); - else if (TREE_CODE (t) == COMPONENT_REF) + if (TREE_CODE (t) == COMPONENT_REF) OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ATTACH_DETACH); else OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_FIRSTPRIVATE_POINTER); + OMP_CLAUSE_MAP_IMPLICIT (c2) = OMP_CLAUSE_MAP_IMPLICIT (c); if (OMP_CLAUSE_MAP_KIND (c2) != GOMP_MAP_FIRSTPRIVATE_POINTER && !c_mark_addressable (t)) return false; @@ -13855,7 +13958,8 @@ tree c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) { bitmap_head generic_head, firstprivate_head, lastprivate_head; - bitmap_head aligned_head, map_head, map_field_head, oacc_reduction_head; + bitmap_head aligned_head, map_head, map_field_head, map_firstprivate_head; + bitmap_head oacc_reduction_head; tree c, t, type, *pc; tree simdlen = NULL_TREE, safelen = NULL_TREE; bool branch_seen = false; @@ -13875,6 +13979,8 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) has been seen, -2 if mixed inscan/normal reduction diagnosed. */ int reduction_seen = 0; bool allocate_seen = false; + bool implicit_moved = false; + bool target_in_reduction_seen = false; bitmap_obstack_initialize (NULL); bitmap_initialize (&generic_head, &bitmap_default_obstack); @@ -13884,8 +13990,9 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) /* If ort == C_ORT_OMP_DECLARE_SIMD used as uniform_head instead. */ bitmap_initialize (&map_head, &bitmap_default_obstack); bitmap_initialize (&map_field_head, &bitmap_default_obstack); + bitmap_initialize (&map_firstprivate_head, &bitmap_default_obstack); /* If ort == C_ORT_OMP used as nontemporal_head or use_device_xxx_head - instead. */ + instead and for ort == C_ORT_OMP_TARGET used as in_reduction_head. */ bitmap_initialize (&oacc_reduction_head, &bitmap_default_obstack); if (ort & C_ORT_ACC) @@ -14037,6 +14144,8 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) case PLUS_EXPR: case MULT_EXPR: case MINUS_EXPR: + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: break; case MIN_EXPR: if (TREE_CODE (type) == COMPLEX_TYPE) @@ -14055,14 +14164,6 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) case BIT_IOR_EXPR: r_name = "|"; break; - case TRUTH_ANDIF_EXPR: - if (FLOAT_TYPE_P (type)) - r_name = "&&"; - break; - case TRUTH_ORIF_EXPR: - if (FLOAT_TYPE_P (type)) - r_name = "||"; - break; default: gcc_unreachable (); } @@ -14284,8 +14385,22 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) || (ort == C_ORT_OMP && (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_USE_DEVICE_PTR || (OMP_CLAUSE_CODE (c) - == OMP_CLAUSE_USE_DEVICE_ADDR)))) + == OMP_CLAUSE_USE_DEVICE_ADDR))) + || (ort == C_ORT_OMP_TARGET + && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION)) { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION + && (bitmap_bit_p (&generic_head, DECL_UID (t)) + || bitmap_bit_p (&firstprivate_head, DECL_UID (t)))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in data-sharing " + "clauses", t); + remove = true; + break; + } + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION) + target_in_reduction_seen = true; if (bitmap_bit_p (&oacc_reduction_head, DECL_UID (t))) { error_at (OMP_CLAUSE_LOCATION (c), @@ -14300,7 +14415,8 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } 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))) + || bitmap_bit_p (&lastprivate_head, DECL_UID (t)) + || bitmap_bit_p (&map_firstprivate_head, DECL_UID (t))) { error_at (OMP_CLAUSE_LOCATION (c), "%qE appears more than once in data clauses", t); @@ -14322,6 +14438,37 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) break; case OMP_CLAUSE_FIRSTPRIVATE: + if (OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c) && !implicit_moved) + { + move_implicit: + implicit_moved = true; + /* Move firstprivate and map clauses with + OMP_CLAUSE_{FIRSTPRIVATE,MAP}_IMPLICIT set to the end of + clauses chain. */ + tree cl1 = NULL_TREE, cl2 = NULL_TREE; + tree *pc1 = pc, *pc2 = &cl1, *pc3 = &cl2; + while (*pc1) + if (OMP_CLAUSE_CODE (*pc1) == OMP_CLAUSE_FIRSTPRIVATE + && OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (*pc1)) + { + *pc3 = *pc1; + pc3 = &OMP_CLAUSE_CHAIN (*pc3); + *pc1 = OMP_CLAUSE_CHAIN (*pc1); + } + else if (OMP_CLAUSE_CODE (*pc1) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_IMPLICIT (*pc1)) + { + *pc2 = *pc1; + pc2 = &OMP_CLAUSE_CHAIN (*pc2); + *pc1 = OMP_CLAUSE_CHAIN (*pc1); + } + else + pc1 = &OMP_CLAUSE_CHAIN (*pc1); + *pc3 = NULL; + *pc2 = cl2; + *pc1 = cl1; + continue; + } t = OMP_CLAUSE_DECL (c); need_complete = true; need_implicitly_determined = true; @@ -14331,8 +14478,13 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) "%qE is not a variable in clause %<firstprivate%>", t); remove = true; } + else if (OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c) + && !OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT_TARGET (c) + && bitmap_bit_p (&map_firstprivate_head, DECL_UID (t))) + remove = true; else if (bitmap_bit_p (&generic_head, DECL_UID (t)) - || bitmap_bit_p (&firstprivate_head, DECL_UID (t))) + || bitmap_bit_p (&firstprivate_head, DECL_UID (t)) + || bitmap_bit_p (&map_firstprivate_head, DECL_UID (t))) { error_at (OMP_CLAUSE_LOCATION (c), "%qE appears more than once in data clauses", t); @@ -14343,6 +14495,9 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) if (ort == C_ORT_ACC) error_at (OMP_CLAUSE_LOCATION (c), "%qD appears more than once in data clauses", t); + else if (OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c) + && !OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT_TARGET (c)) + /* Silently drop the clause. */; else error_at (OMP_CLAUSE_LOCATION (c), "%qD appears both in data and map clauses", t); @@ -14485,6 +14640,9 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } break; } + /* FALLTHRU */ + case OMP_CLAUSE_AFFINITY: + t = OMP_CLAUSE_DECL (c); if (TREE_CODE (t) == TREE_LIST && TREE_PURPOSE (t) && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC) @@ -14503,7 +14661,8 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) { if (handle_omp_array_sections (c, ort)) remove = true; - else if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_DEPOBJ) + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + && OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_DEPOBJ) { error_at (OMP_CLAUSE_LOCATION (c), "%<depend%> clause with %<depobj%> dependence " @@ -14518,17 +14677,22 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) { error_at (OMP_CLAUSE_LOCATION (c), "%qE is not lvalue expression nor array section in " - "%<depend%> clause", t); + "%qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } else if (TREE_CODE (t) == COMPONENT_REF && DECL_C_BIT_FIELD (TREE_OPERAND (t, 1))) { + gcc_assert (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY); error_at (OMP_CLAUSE_LOCATION (c), - "bit-field %qE in %qs clause", t, "depend"); + "bit-field %qE in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } - else if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_DEPOBJ) + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + && OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_DEPOBJ) { if (!c_omp_depend_t_p (TREE_TYPE (t))) { @@ -14539,7 +14703,8 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) remove = true; } } - else if (c_omp_depend_t_p (TREE_TYPE (t))) + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + && c_omp_depend_t_p (TREE_TYPE (t))) { error_at (OMP_CLAUSE_LOCATION (c), "%qE should not have %<omp_depend_t%> type in " @@ -14571,6 +14736,9 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) break; case OMP_CLAUSE_MAP: + if (OMP_CLAUSE_MAP_IMPLICIT (c) && !implicit_moved) + goto move_implicit; + /* FALLTHRU */ case OMP_CLAUSE_TO: case OMP_CLAUSE_FROM: case OMP_CLAUSE__CACHE_: @@ -14604,6 +14772,16 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) { while (TREE_CODE (t) == COMPONENT_REF) t = TREE_OPERAND (t, 0); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_IMPLICIT (c) + && (bitmap_bit_p (&map_head, DECL_UID (t)) + || bitmap_bit_p (&map_field_head, DECL_UID (t)) + || bitmap_bit_p (&map_firstprivate_head, + DECL_UID (t)))) + { + remove = true; + break; + } if (bitmap_bit_p (&map_field_head, DECL_UID (t))) break; if (bitmap_bit_p (&map_head, DECL_UID (t))) @@ -14710,7 +14888,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) if (VAR_P (t) || TREE_CODE (t) == PARM_DECL) { if (bitmap_bit_p (&map_field_head, DECL_UID (t)) - || (ort == C_ORT_OMP + || (ort != C_ORT_ACC && bitmap_bit_p (&map_head, DECL_UID (t)))) break; } @@ -14758,10 +14936,17 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) remove = true; } else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_IMPLICIT (c) + && (bitmap_bit_p (&map_head, DECL_UID (t)) + || bitmap_bit_p (&map_field_head, DECL_UID (t)) + || bitmap_bit_p (&map_firstprivate_head, DECL_UID (t)))) + remove = true; + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER) { if (bitmap_bit_p (&generic_head, DECL_UID (t)) - || bitmap_bit_p (&firstprivate_head, DECL_UID (t))) + || bitmap_bit_p (&firstprivate_head, DECL_UID (t)) + || bitmap_bit_p (&map_firstprivate_head, DECL_UID (t))) { error_at (OMP_CLAUSE_LOCATION (c), "%qD appears more than once in data clauses", t); @@ -14778,10 +14963,10 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) remove = true; } else - bitmap_set_bit (&generic_head, DECL_UID (t)); + bitmap_set_bit (&map_firstprivate_head, DECL_UID (t)); } else if (bitmap_bit_p (&map_head, DECL_UID (t)) - && (ort != C_ORT_OMP + && (ort == C_ORT_ACC || !bitmap_bit_p (&map_field_head, DECL_UID (t)))) { if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) @@ -14795,8 +14980,8 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) "%qD appears more than once in map clauses", t); remove = true; } - else if (bitmap_bit_p (&generic_head, DECL_UID (t)) - && ort == C_ORT_ACC) + else if (ort == C_ORT_ACC + && bitmap_bit_p (&generic_head, DECL_UID (t))) { error_at (OMP_CLAUSE_LOCATION (c), "%qD appears more than once in data clauses", t); @@ -14890,7 +15075,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE) { if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_USE_DEVICE_PTR - && ort == C_ORT_OMP) + && ort != C_ORT_ACC) { error_at (OMP_CLAUSE_LOCATION (c), "%qs variable is not a pointer", @@ -14982,6 +15167,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) case OMP_CLAUSE_THREADS: case OMP_CLAUSE_SIMD: case OMP_CLAUSE_HINT: + case OMP_CLAUSE_FILTER: case OMP_CLAUSE_DEFAULTMAP: case OMP_CLAUSE_BIND: case OMP_CLAUSE_NUM_GANGS: @@ -14998,6 +15184,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) case OMP_CLAUSE_TILE: case OMP_CLAUSE_IF_PRESENT: case OMP_CLAUSE_FINALIZE: + case OMP_CLAUSE_NOHOST: pc = &OMP_CLAUSE_CHAIN (c); continue; @@ -15175,7 +15362,10 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) reduction_seen = -2; } - if (linear_variable_step_check || reduction_seen == -2 || allocate_seen) + if (linear_variable_step_check + || reduction_seen == -2 + || allocate_seen + || target_in_reduction_seen) for (pc = &clauses, c = clauses; c ; c = *pc) { bool remove = false; @@ -15223,6 +15413,20 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION && reduction_seen == -2) OMP_CLAUSE_REDUCTION_INSCAN (c) = 0; + if (target_in_reduction_seen + && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP) + { + tree t = OMP_CLAUSE_DECL (c); + while (handled_component_p (t) + || TREE_CODE (t) == INDIRECT_REF + || TREE_CODE (t) == ADDR_EXPR + || TREE_CODE (t) == MEM_REF + || TREE_CODE (t) == NON_LVALUE_EXPR) + t = TREE_OPERAND (t, 0); + if (DECL_P (t) + && bitmap_bit_p (&oacc_reduction_head, DECL_UID (t))) + OMP_CLAUSE_MAP_IN_REDUCTION (c) = 1; + } if (remove) *pc = OMP_CLAUSE_CHAIN (c); @@ -15313,7 +15517,7 @@ c_omp_clause_copy_ctor (tree clause, tree dst, tree src) tree tmp = create_tmp_var (nonatomic_type); tree tmp_addr = build_fold_addr_expr (tmp); TREE_ADDRESSABLE (tmp) = 1; - TREE_NO_WARNING (tmp) = 1; + suppress_warning (tmp); tree src_addr = build_fold_addr_expr (src); tree dst_addr = build_fold_addr_expr (dst); tree seq_cst = build_int_cst (integer_type_node, MEMMODEL_SEQ_CST); diff --git a/gcc/c/gimple-parser.c b/gcc/c/gimple-parser.c index 58b161b..c8d9db6 100644 --- a/gcc/c/gimple-parser.c +++ b/gcc/c/gimple-parser.c @@ -131,7 +131,7 @@ static void c_parser_gimple_expr_list (gimple_parser &, vec<tree> *); static bool c_parser_gimple_parse_bb_spec (tree val, int *index) { - if (strncmp (IDENTIFIER_POINTER (val), "__BB", 4) != 0) + if (!startswith (IDENTIFIER_POINTER (val), "__BB")) return false; for (const char *p = IDENTIFIER_POINTER (val) + 4; *p; ++p) if (!ISDIGIT (*p)) @@ -877,6 +877,11 @@ c_parser_gimple_statement (gimple_parser &parser, gimple_seq *seq) rhs.value = build3_loc (loc, COND_EXPR, TREE_TYPE (trueval.value), rhs.value, trueval.value, falseval.value); } + if (get_gimple_rhs_class (TREE_CODE (rhs.value)) == GIMPLE_INVALID_RHS) + { + c_parser_error (parser, "unexpected RHS for assignment"); + return; + } assign = gimple_build_assign (lhs.value, rhs.value); gimple_seq_add_stmt_without_update (seq, assign); gimple_set_location (assign, loc); @@ -1754,6 +1759,12 @@ c_parser_gimple_postfix_expression_after_primary (gimple_parser &parser, c_parser_gimple_expr_list (parser, &exprlist); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + if (!FUNC_OR_METHOD_TYPE_P (TREE_TYPE (expr.value))) + { + c_parser_error (parser, "invalid call to non-function"); + expr.set_error (); + break; + } expr.value = build_call_array_loc (expr_loc, TREE_TYPE (TREE_TYPE (expr.value)), expr.value, exprlist.length (), exprlist.address ()); @@ -1887,7 +1898,8 @@ c_parser_gimple_label (gimple_parser &parser, gimple_seq *seq) gcc_assert (c_parser_next_token_is (parser, CPP_COLON)); c_parser_consume_token (parser); tree label = define_label (loc1, name); - gimple_seq_add_stmt_without_update (seq, gimple_build_label (label)); + if (label) + gimple_seq_add_stmt_without_update (seq, gimple_build_label (label)); return; } @@ -2100,6 +2112,14 @@ c_parser_gimple_paren_condition (gimple_parser &parser) if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) return error_mark_node; tree cond = c_parser_gimple_binary_expression (parser).value; + if (cond != error_mark_node + && ! COMPARISON_CLASS_P (cond) + && ! CONSTANT_CLASS_P (cond) + && ! SSA_VAR_P (cond)) + { + c_parser_error (parser, "comparison required"); + cond = error_mark_node; + } if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) return error_mark_node; return cond; |