diff options
Diffstat (limited to 'gcc/c')
-rw-r--r-- | gcc/c/ChangeLog | 385 | ||||
-rw-r--r-- | gcc/c/c-decl.cc | 466 | ||||
-rw-r--r-- | gcc/c/c-errors.cc | 63 | ||||
-rw-r--r-- | gcc/c/c-lang.h | 12 | ||||
-rw-r--r-- | gcc/c/c-objc-common.cc | 7 | ||||
-rw-r--r-- | gcc/c/c-objc-common.h | 12 | ||||
-rw-r--r-- | gcc/c/c-parser.cc | 690 | ||||
-rw-r--r-- | gcc/c/c-tree.h | 25 | ||||
-rw-r--r-- | gcc/c/c-typeck.cc | 708 |
9 files changed, 1816 insertions, 552 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index c8f9206..87a18c9 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,388 @@ +2025-08-07 Jakub Jelinek <jakub@redhat.com> + + PR preprocessor/120778 + * c-decl.cc (c_init_decl_processing): Mark cpp nodes corresponding + to keywords as NODE_WARN if warn_keyword_macro. + +2025-08-06 Alexandre Oliva <oliva@adacore.com> + + * c-tree.h (C_BOOLEAN_TYPE_P): Cover hardbools as well. + * c-typeck.cc (convert_lvalue_to_rvalue): New overload and + wrapper. + (build_atomic_assign, build_modify_expr): Use it. + (build_asm_expr, handle_omp-array_sections_1): Simplify with + it. + (build_unary_op): Handle hardbools. + +2025-08-06 Martin Uecker <uecker@tugraz.at> + + PR c/108931 + * c-typeck.cc (composite_type_cond): Renamed from + composite_type with argument for condition + (composite_type): New function. + (composite_type_internal): Implement new logic. + (build_conditional_expr): Pass condition. + (common_pointer_type): Adapt. + (pointer_diff): Adapt. + (build_binary_op): Adapt. + +2025-08-06 Martin Uecker <uecker@tugraz.at> + + PR c/121217 + * c-typeck.cc (tagged_types_tu_compatible_p): Add check. + +2025-08-06 Kwok Cheung Yeung <kcyeung@baylibre.com> + + * c-parser.cc (c_parser_omp_clause_from_to): Parse 'iterator' modifier. + * c-typeck.cc (c_finish_omp_clauses): Finish iterators for to/from + clauses. + +2025-08-06 Kwok Cheung Yeung <kcyeung@baylibre.com> + Andrew Stubbs <ams@baylibre.com> + + * c-parser.cc (c_parser_omp_variable_list): Use location of the + map expression as the clause location. + (c_parser_omp_clause_map): Parse 'iterator' modifier. + * c-typeck.cc (c_finish_omp_clauses): Finish iterators. Apply + iterators to generated clauses. + +2025-08-02 Martin Uecker <uecker@tugraz.at> + + * c-decl.cc (get_parm_array_spec): Remove. + (push_parm_decl): Do not add `arg spec` attribute. + (build_arg_spec_attribute): New function. + (grokdeklarator): Add `arg spec` attribute. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * c-errors.cc: Update usage of "diagnostic_info" to explicitly + refer to "diagnostics::diagnostic_info". + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * c-errors.cc: Update for diagnostic_t becoming + enum class diagnostics::kind. + * c-parser.cc: Likewise. + * c-typeck.cc: Likewise. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * c-decl.cc: Update for renaming of diagnostic_option_id to + diagnostics::option_id. + * c-errors.cc: Likewise. + * c-tree.h: Likewise. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * c-objc-common.cc: Update for diagnostic_context becoming + diagnostics::context. + * c-tree.h: Likewise. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * c-errors.cc: Update to add "m_" prefix to fields of + diagnostic_info throughout. + +2025-07-21 Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org> + + * c-typeck.cc (build_asm_expr): Pass null pointer to + parse_{input,output}_constraint(). + +2025-07-16 Kwok Cheung Yeung <kcyeung@baylibre.com> + + * c-typeck.cc (handle_omp_array_sections): Use OMP_ITERATOR_DECL_P. + (c_finish_omp_clauses): Likewise. + +2025-07-15 Jakub Jelinek <jakub@redhat.com> + Jason Merrill <jason@redhat.com> + + PR c/44677 + * c-parser.cc (c_parser_unary_expression): Clear DECL_READ_P + after default_function_array_read_conversion for + -Wunused-but-set-{parameter,variable}={2,3} on + PRE{IN,DE}CREMENT_EXPR argument. + (c_parser_postfix_expression_after_primary): Similarly for + POST{IN,DE}CREMENT_EXPR. + * c-decl.cc (pop_scope): Use OPT_Wunused_but_set_variable_ + instead of OPT_Wunused_but_set_variable. + (finish_function): Use OPT_Wunused_but_set_parameter_ + instead of OPT_Wunused_but_set_parameter. + * c-typeck.cc (mark_exp_read): Handle {PRE,POST}{IN,DE}CREMENT_EXPR + and don't handle it when cast to void. + (build_modify_expr): Clear DECL_READ_P after build_binary_op + for -Wunused-but-set-{parameter,variable}=3. + +2025-07-10 Qing Zhao <qing.zhao@oracle.com> + + * c-typeck.cc (build_access_with_size_for_counted_by): Update comments. + Adjust the arguments per the new design. + +2025-07-10 Qing Zhao <qing.zhao@oracle.com> + + PR middle-end/121000 + * c-typeck.cc (build_access_with_size_for_counted_by): Update comments. + Pass TYPE_SIZE_UNIT of the element as the 6th argument. + +2025-07-07 Qing Zhao <qing.zhao@oracle.com> + + Revert: + 2025-07-07 Qing Zhao <qing.zhao@oracle.com> + + * c-decl.cc (verify_counted_by_attribute): Change the 2nd argument + to a vector of fields with counted_by attribute. Verify all fields + in this vector. + (finish_struct): Collect all the fields with counted_by attribute + to a vector and pass this vector to verify_counted_by_attribute. + * c-typeck.cc (build_counted_by_ref): Handle pointers with counted_by. + Add one more argument, issue error when the pointee type is a structure + or union including a flexible array member. + (build_access_with_size_for_counted_by): Handle pointers with counted_by. + (handle_counted_by_for_component_ref): Call build_counted_by_ref + with the new prototype. + +2025-07-01 Qing Zhao <qing.zhao@oracle.com> + + * c-decl.cc (verify_counted_by_attribute): Change the 2nd argument + to a vector of fields with counted_by attribute. Verify all fields + in this vector. + (finish_struct): Collect all the fields with counted_by attribute + to a vector and pass this vector to verify_counted_by_attribute. + * c-typeck.cc (build_counted_by_ref): Handle pointers with counted_by. + Add one more argument, issue error when the pointee type is a structure + or union including a flexible array member. + (build_access_with_size_for_counted_by): Handle pointers with counted_by. + (handle_counted_by_for_component_ref): Call build_counted_by_ref + with the new prototype. + +2025-06-23 Tobias Burnus <tburnus@baylibre.com> + + * c-parser.cc (OACC_WAIT_CLAUSE_MASK): Add if clause. + +2025-06-12 Jakub Jelinek <jakub@redhat.com> + + * c-lang.h (union lang_type::maybe_objc_info): New type. + (struct lang_type): Use union maybe_objc_info info member + instead of tree objc_info. + * c-decl.cc (finish_struct): Allocate struct lang_type using + ggc_internal_cleared_alloc instead of ggc_cleared_alloc, + and use sizeof (struct lang_type) for ObjC and otherwise + offsetof (struct lang_type, info) as size. + (finish_enum): Likewise. + +2025-06-11 Martin Uecker <uecker@tugraz.at> + + PR c/120510 + * c-typeck.cc (composite_type_internal): Activate checking + assertions for all types and also inputs. + (comptypes_for_composite_check): New helper function. + (function_types_compatible_p): Add exception. + +2025-06-11 Martin Uecker <uecker@tugraz.at> + + * c-typeck.cc (function_types_compatible_p): Remove unused + variables and return true/false instead of 1/0. + (type_lists_compatible_p): Return false instead of 0. + +2025-06-11 Martin Uecker <uecker@tugraz.at> + + PR c/120303 + * c-parser.cc (c_parser_generic_selection): Handle error + condition. + +2025-06-09 Martin Uecker <uecker@tugraz.at> + + PR c/120510 + * c-typeck.cc (remove_qualifiers): New function. + (composite_type_internal): Use it. + (comp_target_types): Use it. + (type_lists_compatible_p): Use it. + (find_anonymous_field_with_type): Use it. + (convert_to_anonymous_field): Use it. + (convert_for_assignment): Use it. + +2025-06-09 Martin Uecker <uecker@tugraz.at> + + PR c/120510 + * c-typeck.cc (composite_type_internal): Activate checking + assertion for arrays. + (common_pointer_type): Remove qualifiers also from arrays. + +2025-06-09 Martin Uecker <uecker@tugraz.at> + + PR c/120510 + * c-typeck.cc (composite_types_internal): Handle arrays + declared with atomic for function arguments. + +2025-06-03 Martin Uecker <uecker@tugraz.at> + + * c-typeck.cc (composite_type_internal,composite_type): Move + checking assertions. + +2025-06-03 Martin Uecker <uecker@tugraz.at> + + PR c/116892 + * c-decl.cc (finish_enum): Propagate TYPE_PACKED. + +2025-06-02 Sandra Loosemore <sloosemore@baylibre.com> + + * c-parser.cc (c_parser_omp_context_selector): Call + convert_lvalue_to_rvalue and c_objc_common_truthvalue_conversion + on the expression for OMP_TRAIT_PROPERTY_BOOL_EXPR. + +2025-06-01 Martin Uecker <uecker@tugraz.at> + + PR c/120380 + * c-objc-common.cc (get_aka_type): Ignore attributes for tagged types. + +2025-05-30 Qing Zhao <qing.zhao@oracle.com> + + PR c/120354 + * c-decl.cc (finish_struct): Or the results for TYPE_INCLUDES_FLEXARRAY. + +2025-05-30 Qing Zhao <qing.zhao@oracle.com> + + PR c/120353 + * c-decl.cc (finish_struct): Copy TYPE_INCLUDES_FLEXARRAY marking + to all the variant types of the current structure type. + +2025-05-30 Julian Brown <julian@codesourcery.com> + + * c-decl.cc (c_omp_mapper_id, c_omp_mapper_decl, c_omp_mapper_lookup, + c_omp_extract_mapper_directive, c_omp_map_array_section, + c_omp_scan_mapper_bindings_r, c_omp_scan_mapper_bindings): New + functions. + * c-objc-common.h (LANG_HOOKS_OMP_FINISH_MAPPER_CLAUSES, + LANG_HOOKS_OMP_MAPPER_LOOKUP, LANG_HOOKS_OMP_EXTRACT_MAPPER_DIRECTIVE, + LANG_HOOKS_OMP_MAP_ARRAY_SECTION): Define langhooks for C. + * c-parser.cc (c_parser_omp_clause_map): Add declare_mapper_p + parameter; handle mapper modifier. + (c_parser_omp_all_clauses): Update call to c_parser_omp_clause_map. + (c_parser_omp_target): Instantiate explicit mappers and record bindings + for implicit mappers. + (c_parser_omp_declare_mapper): Parse "declare mapper" directives. + (c_parser_omp_declare): Support "declare mapper". + (c_parser_omp_declare_reduction): Use inform not error_at. + * c-tree.h (c_omp_finish_mapper_clauses, c_omp_mapper_lookup, + c_omp_extract_mapper_directive, c_omp_map_array_section, + c_omp_mapper_id, c_omp_mapper_decl, c_omp_scan_mapper_bindings, + c_omp_instantiate_mappers): Add prototypes. + * c-typeck.cc (c_finish_omp_clauses): Handle GOMP_MAP_PUSH_MAPPER_NAME + and GOMP_MAP_POP_MAPPER_NAME. + (c_omp_finish_mapper_clauses): New function (langhook). + +2025-05-30 Martin Uecker <uecker@tugraz.at> + + PR c/120381 + * c-typeck.cc (composite_type_internal): Stop recursion for + swapped pairs. + +2025-05-29 Sandra Loosemore <sloosemore@baylibre.com> + + * c-parser.cc (c_parser_skip_to_closing_brace): New, copied from + the equivalent function in the C++ front end. + (c_parser_skip_to_end_of_block_or_statement): Pass false to + the error flag. + (c_parser_omp_context_selector): Immediately return error_mark_node + after giving an error that the integer trait property is invalid, + similarly to C++ front end. + (c_parser_omp_context_selector_specification): Likewise handle + error return from c_parser_omp_context_selector similarly to C++. + (c_parser_omp_metadirective): Do not call + c_parser_skip_to_end_of_block_or_statement after an error. + +2025-05-29 Sandra Loosemore <sloosemore@baylibre.com> + + PR c/120180 + * c-parser.cc (c_parser_omp_metadirective): Only consume the + token if it is the expected close paren. + +2025-05-27 Jakub Jelinek <jakub@redhat.com> + + PR c/117025 + * c-parser.cc (c_parser_sizeof_or_countof_expression): Use + C2Y rather than C23 in pedwarn_c23. + +2025-05-27 Alejandro Colomar <alx@kernel.org> + + PR c/117025 + * c-parser.cc (c_parser_sizeof_or_countof_expression): + Add -Wpedantic diagnostic for _Countof in <= C23 mode. + +2025-05-27 Alejandro Colomar <alx@kernel.org> + Martin Uecker <uecker@tugraz.at> + + PR c/117025 + * c-tree.h (in_countof): Add global variable declaration. + (c_expr_countof_expr): Add function prototype. + (c_expr_countof_type): Add function prototype. + * c-decl.cc (start_struct, finish_struct): Add support for + _Countof. + (start_enum, finish_enum): Add support for _Countof. + * c-parser.cc (c_parser_sizeof_expression): New macro. + (c_parser_countof_expression): New macro. + (c_parser_sizeof_or_countof_expression): Rename function and add + support for _Countof. + (c_parser_unary_expression): Add RID_COUNTOF entry. + * c-typeck.cc (in_countof): Add global variable. + (build_external_ref): Add support for _Countof. + (record_maybe_used_decl): Add support for _Countof. + (pop_maybe_used): Add support for _Countof. + (is_top_array_vla): New function. + (c_expr_countof_expr, c_expr_countof_type): New functions. + +2025-05-02 Jakub Jelinek <jakub@redhat.com> + + PR c/120057 + * c-typeck.cc (check_constexpr_init): Handle RAW_DATA_CST. + +2025-05-02 Florian Weimer <fweimer@redhat.com> + + PR c/120055 + * c-typeck.cc (convert_arguments): Check if fundecl is null + before checking for builtin function declaration. + +2025-05-01 Christopher Bazley <chris.bazley@arm.com> + + PR c/119317 + * c-decl.cc (c_get_loop_names): Do not prematurely + end the search for a label that names a loop or + switch statement upon encountering a DEBUG_BEGIN_STMT. + Instead, ignore any instances of DEBUG_BEGIN_STMT. + +2025-05-01 Florian Weimer <fweimer@redhat.com> + + PR c/119950 + * c-typeck.cc (convert_arguments): Check for built-in + function declaration before warning. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * c-decl.cc: Drop include of "make-unique.h". + Replace uses of ::make_unique with std::make_unique. + * c-objc-common.cc: Likewise. + * c-parser.cc: Likewise. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * c-decl.cc: Include "make-unique.h". + (lookup_name_fuzzy): Use ::make_unique rather than "new" when + making suggest_missing_header and suggest_missing_option. + * c-parser.cc: Include "make-unique.h" + (c_parser_error_richloc): Use ::make_unique rather than "new" when + making suggest_missing_header. + +2025-04-28 Andrew Pinski <quic_apinski@quicinc.com> + + PR c/119432 + * gimple-parser.cc (gimple_binary_identifier_code): Add + __ROTATE_LEFT and __ROTATE_RIGHT. + +2025-04-28 Andrew Pinski <quic_apinski@quicinc.com> + + * gimple-parser.cc (gimple_binary_identifier_code): New variable. + (c_parser_gimple_binary_expression): Use gimple_binary_identifier_code + instead of doing if statements on the strings. + 2025-04-27 H.J. Lu <hjl.tools@gmail.com> PR c/48274 diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 4e200f9..8e8bac6 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -1363,7 +1363,7 @@ pop_scope (void) case VAR_DECL: /* Warnings for unused variables. */ if ((!TREE_USED (p) || !DECL_READ_P (p)) - && !warning_suppressed_p (p, OPT_Wunused_but_set_variable) + && !warning_suppressed_p (p, OPT_Wunused_but_set_variable_) && !DECL_IN_SYSTEM_HEADER (p) && DECL_NAME (p) && !DECL_ARTIFICIAL (p) @@ -1377,7 +1377,7 @@ pop_scope (void) } else if (DECL_CONTEXT (p) == current_function_decl) warning_at (DECL_SOURCE_LOCATION (p), - OPT_Wunused_but_set_variable, + OPT_Wunused_but_set_variable_, "variable %qD set but not used", p); } @@ -4556,7 +4556,7 @@ lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc) /* Next, look for exact matches for builtin defines that would have been defined if the user had passed a command-line option (e.g. -fopenmp for "_OPENMP"). */ - diagnostic_option_id option_id + diagnostics::option_id option_id = get_option_for_builtin_define (IDENTIFIER_POINTER (name)); if (option_id.m_idx > 0) return name_hint @@ -4825,6 +4825,29 @@ c_init_decl_processing (void) make_fname_decl = c_make_fname_decl; start_fname_decls (); + + if (warn_keyword_macro) + { + for (unsigned int i = 0; i < num_c_common_reswords; ++i) + /* For C register keywords which don't start with underscore + or start with just single underscore. Don't complain about + ObjC or Transactional Memory keywords. */ + if (c_common_reswords[i].word[0] == '_' + && c_common_reswords[i].word[1] == '_') + continue; + else if (c_common_reswords[i].disable + & (D_TRANSMEM | D_OBJC | D_CXX_OBJC)) + continue; + else + { + tree id = get_identifier (c_common_reswords[i].word); + if (C_IS_RESERVED_WORD (id) + && C_RID_CODE (id) != RID_CXX_COMPAT_WARN) + cpp_lookup (parse_in, + (const unsigned char *) IDENTIFIER_POINTER (id), + IDENTIFIER_LENGTH (id))->flags |= NODE_WARN; + } + } } /* Create the VAR_DECL at LOC for __FUNCTION__ etc. ID is the name to @@ -6208,184 +6231,7 @@ grokparm (const struct c_parm *parm, tree *expr) return decl; } -/* Return attribute "arg spec" corresponding to an array/VLA parameter - described by PARM, concatenated onto attributes ATTRS. - The spec consists of one dollar symbol for each specified variable - bound, one asterisk for each unspecified variable bound, followed - by at most one specification of the most significant bound of - an ordinary array parameter. For ordinary arrays the specification - is either the constant bound itself, or the space character for - an array with an unspecified bound (the [] form). Finally, a chain - of specified variable bounds is appended to the spec, starting with - the most significant bound. For example, the PARM T a[2][m][3][n] - will produce __attribute__((arg spec ("[$$2]", m, n)). - For T a typedef for an array with variable bounds, the bounds are - included in the specification in the expected order. - No "arg spec" is created for parameters of pointer types, making - a distinction between T(*)[N] (or, equivalently, T[][N]) and - the T[M][N] form, all of which have the same type and are represented - the same, but only the last of which gets an "arg spec" describing - the most significant bound M. */ - -static tree -get_parm_array_spec (const struct c_parm *parm, tree attrs) -{ - /* The attribute specification string, minor bound first. */ - std::string spec; - - /* A list of VLA variable bounds, major first, or null if unspecified - or not a VLA. */ - tree vbchain = NULL_TREE; - /* True for a pointer parameter. */ - bool pointer = false; - /* True for an ordinary array with an unpecified bound. */ - bool nobound = false; - - /* Create a string representation for the bounds of the array/VLA. */ - for (c_declarator *pd = parm->declarator, *next; pd; pd = next) - { - next = pd->declarator; - while (next && next->kind == cdk_attrs) - next = next->declarator; - - /* Remember if a pointer has been seen to avoid storing the constant - bound. */ - if (pd->kind == cdk_pointer) - pointer = true; - - if ((pd->kind == cdk_pointer || pd->kind == cdk_function) - && (!next || next->kind == cdk_id)) - { - /* Do nothing for the common case of a pointer. The fact that - the parameter is one can be deduced from the absence of - an arg spec for it. */ - return attrs; - } - - if (pd->kind == cdk_id) - { - if (pointer - || !parm->specs->type - || TREE_CODE (parm->specs->type) != ARRAY_TYPE - || !TYPE_DOMAIN (parm->specs->type) - || !TYPE_MAX_VALUE (TYPE_DOMAIN (parm->specs->type))) - continue; - - tree max = TYPE_MAX_VALUE (TYPE_DOMAIN (parm->specs->type)); - if (!vbchain - && TREE_CODE (max) == INTEGER_CST) - { - /* Extract the upper bound from a parameter of an array type - unless the parameter is an ordinary array of unspecified - bound in which case a next iteration of the loop will - exit. */ - if (spec.empty () || spec.end ()[-1] != ' ') - { - if (!tree_fits_shwi_p (max)) - continue; - - /* The upper bound is the value of the largest valid - index. */ - HOST_WIDE_INT n = tree_to_shwi (max) + 1; - char buf[40]; - sprintf (buf, HOST_WIDE_INT_PRINT_UNSIGNED, n); - spec += buf; - } - continue; - } - - /* For a VLA typedef, create a list of its variable bounds and - append it in the expected order to VBCHAIN. */ - tree tpbnds = NULL_TREE; - for (tree type = parm->specs->type; TREE_CODE (type) == ARRAY_TYPE; - type = TREE_TYPE (type)) - { - tree nelts_minus_one = array_type_nelts_minus_one (type); - if (error_operand_p (nelts_minus_one)) - return attrs; - if (TREE_CODE (nelts_minus_one) != INTEGER_CST) - { - /* Each variable VLA bound is represented by the dollar - sign. */ - spec += "$"; - tpbnds = tree_cons (NULL_TREE, nelts_minus_one, tpbnds); - } - } - tpbnds = nreverse (tpbnds); - vbchain = chainon (vbchain, tpbnds); - continue; - } - - if (pd->kind != cdk_array) - continue; - - if (pd->u.array.vla_unspec_p) - { - /* Each unspecified bound is represented by a star. There - can be any number of these in a declaration (but none in - a definition). */ - spec += '*'; - continue; - } - - tree nelts = pd->u.array.dimen; - if (!nelts) - { - /* Ordinary array of unspecified size. There can be at most - one for the most significant bound. Exit on the next - iteration which determines whether or not PARM is declared - as a pointer or an array. */ - nobound = true; - continue; - } - - if (pd->u.array.static_p) - spec += 's'; - - if (!INTEGRAL_TYPE_P (TREE_TYPE (nelts))) - /* Avoid invalid NELTS. */ - return attrs; - - STRIP_NOPS (nelts); - nelts = c_fully_fold (nelts, false, nullptr); - if (TREE_CODE (nelts) == INTEGER_CST) - { - /* Skip all constant bounds except the most significant one. - The interior ones are included in the array type. */ - if (next && (next->kind == cdk_array || next->kind == cdk_pointer)) - continue; - - if (!tree_fits_uhwi_p (nelts)) - /* Bail completely on invalid bounds. */ - return attrs; - - char buf[40]; - unsigned HOST_WIDE_INT n = tree_to_uhwi (nelts); - sprintf (buf, HOST_WIDE_INT_PRINT_UNSIGNED, n); - spec += buf; - break; - } - - /* Each variable VLA bound is represented by a dollar sign. */ - spec += "$"; - vbchain = tree_cons (NULL_TREE, nelts, vbchain); - } - - if (spec.empty () && !nobound) - return attrs; - spec.insert (0, "["); - if (nobound) - /* Ordinary array of unspecified bound is represented by a space. - It must be last in the spec. */ - spec += ' '; - spec += ']'; - - tree acsstr = build_string (spec.length () + 1, spec.c_str ()); - tree args = tree_cons (NULL_TREE, acsstr, vbchain); - tree name = get_identifier ("arg spec"); - return tree_cons (name, args, attrs); -} /* Given a parsed parameter declaration, decode it into a PARM_DECL and push that on the current scope. EXPR is a pointer to an @@ -6401,7 +6247,6 @@ push_parm_decl (const struct c_parm *parm, tree *expr) if (decl && DECL_P (decl)) DECL_SOURCE_LOCATION (decl) = parm->loc; - attrs = get_parm_array_spec (parm, attrs); decl_attributes (&decl, attrs, 0); decl = pushdecl (decl); @@ -6775,6 +6620,25 @@ add_decl_expr (location_t loc, tree type, tree *expr, bool set_name_p) } } + +/* Add attribute "arg spec" to ATTRS corresponding to an array/VLA parameter + declared with type TYPE. The attribute has two arguments. The first is + a string that encodes the presence of the static keyword. The second is + the declared type of the array before adjustment, i.e. as an array type + including the outermost bound. */ + +static tree +build_arg_spec_attribute (tree type, bool static_p, tree attrs) +{ + tree vbchain = tree_cons (NULL_TREE, type, NULL_TREE); + tree acsstr = static_p ? build_string (7, "static") : + build_string (1, ""); + tree args = tree_cons (NULL_TREE, acsstr, vbchain); + tree name = get_identifier ("arg spec"); + return tree_cons (name, args, attrs); +} + + /* Given declspecs and a declarator, determine the name and type of the object declared and construct a ..._DECL node for it. @@ -6834,6 +6698,7 @@ grokdeclarator (const struct c_declarator *declarator, bool funcdef_flag = false; bool funcdef_syntax = false; bool size_varies = false; + bool size_error = false; tree decl_attr = declspecs->decl_attr; int array_ptr_quals = TYPE_UNQUALIFIED; tree array_ptr_attrs = NULL_TREE; @@ -7326,6 +7191,7 @@ grokdeclarator (const struct c_declarator *declarator, "size of unnamed array has non-integer type"); size = integer_one_node; size_int_const = true; + size_error = true; } /* This can happen with enum forward declaration. */ else if (!COMPLETE_TYPE_P (TREE_TYPE (size))) @@ -7338,6 +7204,7 @@ grokdeclarator (const struct c_declarator *declarator, "type"); size = integer_one_node; size_int_const = true; + size_error = true; } size = c_fully_fold (size, false, &size_maybe_const); @@ -7363,6 +7230,7 @@ grokdeclarator (const struct c_declarator *declarator, error_at (loc, "size of unnamed array is negative"); size = integer_one_node; size_int_const = true; + size_error = true; } /* Handle a size folded to an integer constant but not an integer constant expression. */ @@ -7978,6 +7846,10 @@ grokdeclarator (const struct c_declarator *declarator, if (TREE_CODE (type) == ARRAY_TYPE) { + if (!size_error) + *decl_attrs = build_arg_spec_attribute (type, array_parm_static, + *decl_attrs); + /* Transfer const-ness of array into that of type pointed to. */ type = TREE_TYPE (type); if (orig_qual_type != NULL_TREE) @@ -8943,12 +8815,14 @@ start_struct (location_t loc, enum tree_code code, tree name, within a statement expr used within sizeof, et. al. This is not terribly serious as C++ doesn't permit statement exprs within sizeof anyhow. */ - if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof)) + if (warn_cxx_compat + && (in_sizeof || in_typeof || in_alignof || in_countof)) warning_at (loc, OPT_Wc___compat, "defining type in %qs expression is invalid in C++", - (in_sizeof - ? "sizeof" - : (in_typeof ? "typeof" : "alignof"))); + (in_sizeof ? "sizeof" + : in_typeof ? "typeof" + : in_alignof ? "alignof" + : "_Countof")); if (in_underspecified_init) error_at (loc, "%qT defined in underspecified object initializer", ref); @@ -9647,15 +9521,18 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, DECL_NOT_FLEXARRAY (x) = !is_flexible_array_member_p (is_last_field, x); /* Set TYPE_INCLUDES_FLEXARRAY for the context of x, t. - when x is an array and is the last field. */ + when x is an array and is the last field. + There is only one last_field for a structure type, but there might + be multiple last_fields for a union type, therefore we should ORed + the result for multiple last_fields. */ if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE) TYPE_INCLUDES_FLEXARRAY (t) - = is_last_field && c_flexible_array_member_type_p (TREE_TYPE (x)); + |= is_last_field && c_flexible_array_member_type_p (TREE_TYPE (x)); /* Recursively set TYPE_INCLUDES_FLEXARRAY for the context of x, t when x is an union or record and is the last field. */ else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (x))) TYPE_INCLUDES_FLEXARRAY (t) - = is_last_field && TYPE_INCLUDES_FLEXARRAY (TREE_TYPE (x)); + |= is_last_field && TYPE_INCLUDES_FLEXARRAY (TREE_TYPE (x)); if (warn_flex_array_member_not_at_end && !is_last_field @@ -9785,12 +9662,17 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, len += list_length (x); /* Use the same allocation policy here that make_node uses, to - ensure that this lives as long as the rest of the struct decl. - All decls in an inline function need to be saved. */ - - space = ggc_cleared_alloc<struct lang_type> (); - space2 = (sorted_fields_type *) ggc_internal_alloc - (sizeof (struct sorted_fields_type) + len * sizeof (tree)); + ensure that this lives as long as the rest of the struct decl. + All decls in an inline function need to be saved. */ + + space = ((struct lang_type *) + ggc_internal_cleared_alloc (c_dialect_objc () + ? sizeof (struct lang_type) + : offsetof (struct lang_type, + info))); + space2 = ((sorted_fields_type *) + ggc_internal_alloc (sizeof (struct sorted_fields_type) + + len * sizeof (tree))); len = 0; space->s = space2; @@ -9891,6 +9773,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, C_TYPE_VARIABLE_SIZE (x) = C_TYPE_VARIABLE_SIZE (t); C_TYPE_VARIABLY_MODIFIED (x) = C_TYPE_VARIABLY_MODIFIED (t); C_TYPE_INCOMPLETE_VARS (x) = NULL_TREE; + TYPE_INCLUDES_FLEXARRAY (x) = TYPE_INCLUDES_FLEXARRAY (t); } /* Update type location to the one of the definition, instead of e.g. @@ -9923,7 +9806,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, struct_types. */ if (warn_cxx_compat && struct_parse_info != NULL - && !in_sizeof && !in_typeof && !in_alignof) + && !in_sizeof && !in_typeof && !in_alignof && !in_countof) struct_parse_info->struct_types.safe_push (t); } @@ -10097,12 +9980,14 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name, /* FIXME: This will issue a warning for a use of a type defined within sizeof in a statement expr. This is not terribly serious as C++ doesn't permit statement exprs within sizeof anyhow. */ - if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof)) + if (warn_cxx_compat + && (in_sizeof || in_typeof || in_alignof || in_countof)) warning_at (loc, OPT_Wc___compat, "defining type in %qs expression is invalid in C++", - (in_sizeof - ? "sizeof" - : (in_typeof ? "typeof" : "alignof"))); + (in_sizeof ? "sizeof" + : in_typeof ? "typeof" + : in_alignof ? "alignof" + : "_Countof")); if (in_underspecified_init) error_at (loc, "%qT defined in underspecified object initializer", @@ -10261,7 +10146,10 @@ finish_enum (tree enumtype, tree values, tree attributes) /* Record the min/max values so that we can warn about bit-field enumerations that are too small for the values. */ - lt = ggc_cleared_alloc<struct lang_type> (); + lt = ((struct lang_type *) + ggc_internal_cleared_alloc (c_dialect_objc () + ? sizeof (struct lang_type) + : offsetof (struct lang_type, info))); lt->enum_min = minnode; lt->enum_max = maxnode; TYPE_LANG_SPECIFIC (enumtype) = lt; @@ -10285,6 +10173,7 @@ finish_enum (tree enumtype, tree values, tree attributes) TYPE_UNSIGNED (tem) = TYPE_UNSIGNED (enumtype); TYPE_LANG_SPECIFIC (tem) = TYPE_LANG_SPECIFIC (enumtype); ENUM_UNDERLYING_TYPE (tem) = ENUM_UNDERLYING_TYPE (enumtype); + TYPE_PACKED (tem) = TYPE_PACKED (enumtype); } /* Finish debugging output for this type. */ @@ -10296,7 +10185,7 @@ finish_enum (tree enumtype, tree values, tree attributes) struct_types. */ if (warn_cxx_compat && struct_parse_info != NULL - && !in_sizeof && !in_typeof && !in_alignof) + && !in_sizeof && !in_typeof && !in_alignof && !in_countof) struct_parse_info->struct_types.safe_push (enumtype); /* Check for consistency with previous definition */ @@ -11448,9 +11337,9 @@ finish_function (location_t end_loc) && !DECL_READ_P (decl) && DECL_NAME (decl) && !DECL_ARTIFICIAL (decl) - && !warning_suppressed_p (decl, OPT_Wunused_but_set_parameter)) + && !warning_suppressed_p (decl, OPT_Wunused_but_set_parameter_)) warning_at (DECL_SOURCE_LOCATION (decl), - OPT_Wunused_but_set_parameter, + OPT_Wunused_but_set_parameter_, "parameter %qD set but not used", decl); } @@ -13819,6 +13708,174 @@ c_check_omp_declare_reduction_r (tree *tp, int *, void *data) return NULL_TREE; } +/* Return identifier to look up for omp declare mapper. */ + +tree +c_omp_mapper_id (tree mapper_id) +{ + const char *p = NULL; + + const char prefix[] = "omp declare mapper "; + + if (mapper_id == NULL_TREE) + p = "<default>"; + else if (TREE_CODE (mapper_id) == IDENTIFIER_NODE) + p = IDENTIFIER_POINTER (mapper_id); + else + return error_mark_node; + + size_t lenp = sizeof (prefix); + size_t len = strlen (p); + char *name = XALLOCAVEC (char, lenp + len); + memcpy (name, prefix, lenp - 1); + memcpy (name + lenp - 1, p, len + 1); + return get_identifier (name); +} + +/* Lookup MAPPER_ID in the current scope, or create an artificial + VAR_DECL, bind it into the current scope and return it. */ + +tree +c_omp_mapper_decl (tree mapper_id) +{ + struct c_binding *b = I_SYMBOL_BINDING (mapper_id); + if (b != NULL && B_IN_CURRENT_SCOPE (b)) + return b->decl; + + tree decl = build_decl (BUILTINS_LOCATION, VAR_DECL, + mapper_id, integer_type_node); + DECL_ARTIFICIAL (decl) = 1; + DECL_EXTERNAL (decl) = 1; + TREE_STATIC (decl) = 1; + TREE_PUBLIC (decl) = 0; + bind (mapper_id, decl, current_scope, true, false, BUILTINS_LOCATION); + return decl; +} + +/* Lookup MAPPER_ID in the first scope where it has entry for TYPE. */ + +tree +c_omp_mapper_lookup (tree mapper_id, tree type) +{ + if (!RECORD_OR_UNION_TYPE_P (type)) + return NULL_TREE; + + mapper_id = c_omp_mapper_id (mapper_id); + + struct c_binding *b = I_SYMBOL_BINDING (mapper_id); + while (b) + { + tree t; + for (t = DECL_INITIAL (b->decl); t; t = TREE_CHAIN (t)) + if (comptypes (TREE_PURPOSE (t), type)) + return TREE_VALUE (t); + b = b->shadowed; + } + return NULL_TREE; +} + +/* For C, we record a pointer to the mapper itself without wrapping it in an + artificial function or similar. So, just return it. */ + +tree +c_omp_extract_mapper_directive (tree mapper) +{ + return mapper; +} + +/* For now we can handle singleton OMP_ARRAY_SECTIONs with custom mappers, but + nothing more complicated. */ + +tree +c_omp_map_array_section (location_t loc, tree t) +{ + tree low = TREE_OPERAND (t, 1); + tree len = TREE_OPERAND (t, 2); + + if (len && integer_onep (len)) + { + t = TREE_OPERAND (t, 0); + + if (!low) + low = integer_zero_node; + + t = build_array_ref (loc, t, low); + } + + return t; +} + +/* Helper function for below function. */ + +static tree +c_omp_scan_mapper_bindings_r (tree *tp, int *walk_subtrees, void *ptr) +{ + tree t = *tp; + omp_mapper_list<tree> *mlist = (omp_mapper_list<tree> *) ptr; + tree aggr_type = NULL_TREE; + + if (TREE_CODE (t) == SIZEOF_EXPR + || TREE_CODE (t) == ALIGNOF_EXPR) + { + *walk_subtrees = 0; + return NULL_TREE; + } + + if (TREE_CODE (t) == OMP_CLAUSE) + return NULL_TREE; + + if (TREE_CODE (t) == COMPONENT_REF + && RECORD_OR_UNION_TYPE_P (TREE_TYPE (TREE_OPERAND (t, 0)))) + aggr_type = TREE_TYPE (TREE_OPERAND (t, 0)); + else if ((TREE_CODE (t) == VAR_DECL + || TREE_CODE (t) == PARM_DECL + || TREE_CODE (t) == RESULT_DECL) + && RECORD_OR_UNION_TYPE_P (TREE_TYPE (t))) + aggr_type = TREE_TYPE (t); + + if (aggr_type) + { + tree mapper_fn = c_omp_mapper_lookup (NULL_TREE, aggr_type); + if (mapper_fn) + mlist->add_mapper (NULL_TREE, aggr_type, mapper_fn); + } + + return NULL_TREE; +} + +/* Scan an offload region's body, and record uses of struct- or union-typed + variables. Add _mapper_binding_ fake clauses to *CLAUSES_PTR. */ + +void +c_omp_scan_mapper_bindings (location_t loc, tree *clauses_ptr, tree body) +{ + hash_set<omp_name_type<tree>> seen_types; + auto_vec<tree> mappers; + omp_mapper_list<tree> mlist (&seen_types, &mappers); + + walk_tree_without_duplicates (&body, c_omp_scan_mapper_bindings_r, &mlist); + + unsigned int i; + tree mapper; + FOR_EACH_VEC_ELT (mappers, i, mapper) + c_omp_find_nested_mappers (&mlist, mapper); + + FOR_EACH_VEC_ELT (mappers, i, mapper) + { + if (mapper == error_mark_node) + continue; + tree mapper_name = OMP_DECLARE_MAPPER_ID (mapper); + tree decl = OMP_DECLARE_MAPPER_DECL (mapper); + + tree c = build_omp_clause (loc, OMP_CLAUSE__MAPPER_BINDING_); + OMP_CLAUSE__MAPPER_BINDING__ID (c) = mapper_name; + OMP_CLAUSE__MAPPER_BINDING__DECL (c) = decl; + OMP_CLAUSE__MAPPER_BINDING__MAPPER (c) = mapper; + + OMP_CLAUSE_CHAIN (c) = *clauses_ptr; + *clauses_ptr = c; + } +} bool c_check_in_current_scope (tree decl) @@ -13861,7 +13918,8 @@ c_get_loop_names (tree before_labels, bool switch_p, tree *last_p) ++ret; } } - else if (TREE_CODE (stmt) != CASE_LABEL_EXPR) + else if (TREE_CODE (stmt) != CASE_LABEL_EXPR + && TREE_CODE (stmt) != DEBUG_BEGIN_STMT) break; } if (last) diff --git a/gcc/c/c-errors.cc b/gcc/c/c-errors.cc index 4682dca..e2c74fe 100644 --- a/gcc/c/c-errors.cc +++ b/gcc/c/c-errors.cc @@ -33,10 +33,10 @@ along with GCC; see the file COPYING3. If not see bool pedwarn_c23 (location_t location, - diagnostic_option_id option_id, + diagnostics::option_id option_id, const char *gmsgid, ...) { - diagnostic_info diagnostic; + diagnostics::diagnostic_info diagnostic; va_list ap; bool warned = false; rich_location richloc (line_table, location); @@ -48,8 +48,9 @@ pedwarn_c23 (location_t location, { diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, (pedantic && !flag_isoc2y) - ? DK_PEDWARN : DK_WARNING); - diagnostic.option_id = OPT_Wc23_c2y_compat; + ? diagnostics::kind::pedwarn + : diagnostics::kind::warning); + diagnostic.m_option_id = OPT_Wc23_c2y_compat; warned = diagnostic_report_diagnostic (global_dc, &diagnostic); } /* -Wno-c23-c2y-compat suppresses even the pedwarns. */ @@ -58,8 +59,9 @@ pedwarn_c23 (location_t location, /* For -pedantic outside C2Y, issue a pedwarn. */ else if (pedantic && !flag_isoc2y) { - diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN); - diagnostic.option_id = option_id; + diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, + diagnostics::kind::pedwarn); + diagnostic.m_option_id = option_id; warned = diagnostic_report_diagnostic (global_dc, &diagnostic); } va_end (ap); @@ -77,10 +79,10 @@ pedwarn_c23 (location_t location, bool pedwarn_c11 (location_t location, - diagnostic_option_id option_id, + diagnostics::option_id option_id, const char *gmsgid, ...) { - diagnostic_info diagnostic; + diagnostics::diagnostic_info diagnostic; va_list ap; bool warned = false; rich_location richloc (line_table, location); @@ -93,11 +95,12 @@ pedwarn_c11 (location_t location, { diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, (pedantic && !flag_isoc23) - ? DK_PEDWARN : DK_WARNING); + ? diagnostics::kind::pedwarn + : diagnostics::kind::warning); if (option_id == OPT_Wpedantic) - diagnostic.option_id = OPT_Wc11_c23_compat; + diagnostic.m_option_id = OPT_Wc11_c23_compat; else - diagnostic.option_id = option_id; + diagnostic.m_option_id = option_id; warned = diagnostic_report_diagnostic (global_dc, &diagnostic); } /* -Wno-c11-c23-compat suppresses even the pedwarns. */ @@ -106,8 +109,9 @@ pedwarn_c11 (location_t location, /* For -pedantic outside C23, issue a pedwarn. */ else if (pedantic && !flag_isoc23) { - diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN); - diagnostic.option_id = option_id; + diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, + diagnostics::kind::pedwarn); + diagnostic.m_option_id = option_id; warned = diagnostic_report_diagnostic (global_dc, &diagnostic); } va_end (ap); @@ -122,10 +126,10 @@ pedwarn_c11 (location_t location, bool pedwarn_c99 (location_t location, - diagnostic_option_id option_id, + diagnostics::option_id option_id, const char *gmsgid, ...) { - diagnostic_info diagnostic; + diagnostics::diagnostic_info diagnostic; va_list ap; bool warned = false; rich_location richloc (line_table, location); @@ -137,8 +141,9 @@ pedwarn_c99 (location_t location, { diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, (pedantic && !flag_isoc11) - ? DK_PEDWARN : DK_WARNING); - diagnostic.option_id = OPT_Wc99_c11_compat; + ? diagnostics::kind::pedwarn + : diagnostics::kind::warning); + diagnostic.m_option_id = OPT_Wc99_c11_compat; warned = diagnostic_report_diagnostic (global_dc, &diagnostic); } /* -Wno-c99-c11-compat suppresses even the pedwarns. */ @@ -147,8 +152,9 @@ pedwarn_c99 (location_t location, /* For -pedantic outside C11, issue a pedwarn. */ else if (pedantic && !flag_isoc11) { - diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN); - diagnostic.option_id = option_id; + diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, + diagnostics::kind::pedwarn); + diagnostic.m_option_id = option_id; warned = diagnostic_report_diagnostic (global_dc, &diagnostic); } va_end (ap); @@ -164,10 +170,10 @@ pedwarn_c99 (location_t location, bool pedwarn_c90 (location_t location, - diagnostic_option_id option_id, + diagnostics::option_id option_id, const char *gmsgid, ...) { - diagnostic_info diagnostic; + diagnostics::diagnostic_info diagnostic; va_list ap; bool warned = false; rich_location richloc (line_table, location); @@ -183,8 +189,9 @@ pedwarn_c90 (location_t location, { diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, (pedantic && !flag_isoc99) - ? DK_PEDWARN : DK_WARNING); - diagnostic.option_id = option_id; + ? diagnostics::kind::pedwarn + : diagnostics::kind::warning); + diagnostic.m_option_id = option_id; diagnostic_report_diagnostic (global_dc, &diagnostic); warned = true; goto out; @@ -196,8 +203,9 @@ pedwarn_c90 (location_t location, { diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, (pedantic && !flag_isoc99) - ? DK_PEDWARN : DK_WARNING); - diagnostic.option_id = OPT_Wc90_c99_compat; + ? diagnostics::kind::pedwarn + : diagnostics::kind::warning); + diagnostic.m_option_id = OPT_Wc90_c99_compat; diagnostic_report_diagnostic (global_dc, &diagnostic); } /* -Wno-c90-c99-compat suppresses the pedwarns. */ @@ -206,8 +214,9 @@ pedwarn_c90 (location_t location, /* For -pedantic outside C99, issue a pedwarn. */ else if (pedantic && !flag_isoc99) { - diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN); - diagnostic.option_id = option_id; + diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, + diagnostics::kind::pedwarn); + diagnostic.m_option_id = option_id; diagnostic_report_diagnostic (global_dc, &diagnostic); warned = true; } diff --git a/gcc/c/c-lang.h b/gcc/c/c-lang.h index 4b93d18..2e99b4d 100644 --- a/gcc/c/c-lang.h +++ b/gcc/c/c-lang.h @@ -35,10 +35,14 @@ struct GTY(()) lang_type { /* In an ENUMERAL_TYPE, the min and max values. */ tree enum_min; tree enum_max; - /* In a RECORD_TYPE, information specific to Objective-C, such - as a list of adopted protocols or a pointer to a corresponding - @interface. See objc/objc-act.h for details. */ - tree objc_info; + union maybe_objc_info { + /* If not c_dialect_objc, this part is not even allocated. */ + char GTY((tag ("0"))) non_objc; + /* In a RECORD_TYPE, information specific to Objective-C, such + as a list of adopted protocols or a pointer to a corresponding + @interface. See objc/objc-act.h for details. */ + tree GTY((tag ("1"))) objc_info; + } GTY ((desc ("c_dialect_objc ()"))) info; }; struct GTY(()) lang_decl { diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc index 2016eae..5c50983 100644 --- a/gcc/c/c-objc-common.cc +++ b/gcc/c/c-objc-common.cc @@ -216,6 +216,11 @@ get_aka_type (tree type) return canonical ? canonical : type; } } + /* For tagged types ignore attributes because they will otherwise + be ignored later causing a warning inside diagnostics which leads + to an ICE. */ + if (RECORD_OR_UNION_TYPE_P (type) || TREE_CODE (type) == ENUMERAL_TYPE) + return build_qualified_type (result, TYPE_QUALS (type)); return build_type_attribute_qual_variant (result, TYPE_ATTRIBUTES (type), TYPE_QUALS (type)); } @@ -409,7 +414,7 @@ has_c_linkage (const_tree decl ATTRIBUTE_UNUSED) } void -c_initialize_diagnostics (diagnostic_context *context) +c_initialize_diagnostics (diagnostics::context *context) { context->set_pretty_printer (std::make_unique<c_pretty_printer> ()); c_common_diagnostics_set_defaults (context); diff --git a/gcc/c/c-objc-common.h b/gcc/c/c-objc-common.h index 84bd357..84f6fd3 100644 --- a/gcc/c/c-objc-common.h +++ b/gcc/c/c-objc-common.h @@ -137,6 +137,18 @@ static const scoped_attribute_specs *const c_objc_attribute_table[] = #undef LANG_HOOKS_OMP_CLAUSE_ASSIGN_OP #define LANG_HOOKS_OMP_CLAUSE_ASSIGN_OP c_omp_clause_copy_ctor +#undef LANG_HOOKS_OMP_FINISH_MAPPER_CLAUSES +#define LANG_HOOKS_OMP_FINISH_MAPPER_CLAUSES c_omp_finish_mapper_clauses + +#undef LANG_HOOKS_OMP_MAPPER_LOOKUP +#define LANG_HOOKS_OMP_MAPPER_LOOKUP c_omp_mapper_lookup + +#undef LANG_HOOKS_OMP_EXTRACT_MAPPER_DIRECTIVE +#define LANG_HOOKS_OMP_EXTRACT_MAPPER_DIRECTIVE c_omp_extract_mapper_directive + +#undef LANG_HOOKS_OMP_MAP_ARRAY_SECTION +#define LANG_HOOKS_OMP_MAP_ARRAY_SECTION c_omp_map_array_section + #undef LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P #define LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P c_var_mod_p #endif /* GCC_C_OBJC_COMMON */ diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 8a63dc5..814accf 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -77,7 +77,7 @@ along with GCC; see the file COPYING3. If not see #include "asan.h" #include "c-family/c-ubsan.h" #include "gcc-urlifier.h" - + /* We need to walk over decls with incomplete struct/union/enum types after parsing the whole translation unit. In finish_decl(), if the decl is static, has incomplete @@ -1420,6 +1420,51 @@ c_parser_skip_to_end_of_parameter (c_parser *parser) parser->error = false; } +/* Skip tokens until a non-nested closing curly brace is the next + token, or there are no more tokens. Return true in the first case, + false otherwise. */ + +static bool +c_parser_skip_to_closing_brace (c_parser *parser) +{ + unsigned nesting_depth = 0; + + while (true) + { + c_token *token = c_parser_peek_token (parser); + + switch (token->type) + { + case CPP_PRAGMA_EOL: + if (!parser->in_pragma) + break; + /* FALLTHRU */ + case CPP_EOF: + /* If we've run out of tokens, stop. */ + return false; + + case CPP_CLOSE_BRACE: + /* If the next token is a non-nested `}', then we have reached + the end of the current block. */ + if (nesting_depth-- == 0) + return true; + break; + + case CPP_OPEN_BRACE: + /* If it the next token is a `{', then we are entering a new + block. Consume the entire block. */ + ++nesting_depth; + break; + + default: + break; + } + + /* Consume the token. */ + c_parser_consume_token (parser); + } +} + /* Expect to be at the end of the pragma directive and consume an end of line marker. */ @@ -1535,7 +1580,7 @@ c_parser_skip_to_end_of_block_or_statement (c_parser *parser, here for secondary error recovery, after parser->error has been cleared. */ c_parser_consume_pragma (parser); - c_parser_skip_to_pragma_eol (parser); + c_parser_skip_to_pragma_eol (parser, false); parser->error = save_error; continue; @@ -1737,7 +1782,10 @@ static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *, tree); static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *); static struct c_expr c_parser_unary_expression (c_parser *); -static struct c_expr c_parser_sizeof_expression (c_parser *); +static inline struct c_expr c_parser_sizeof_expression (c_parser *); +static inline struct c_expr c_parser_countof_expression (c_parser *); +static struct c_expr c_parser_sizeof_or_countof_expression (c_parser *, + enum rid); static struct c_expr c_parser_alignof_expression (c_parser *); static struct c_expr c_parser_postfix_expression (c_parser *); static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *, @@ -10452,9 +10500,13 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after) ++ unary-expression -- unary-expression unary-operator cast-expression + _Countof unary-expression + _Countof ( type-name ) sizeof unary-expression sizeof ( type-name ) + (_Countof is new in C2y.) + unary-operator: one of & * + - ~ ! @@ -10495,15 +10547,31 @@ c_parser_unary_expression (c_parser *parser) c_parser_consume_token (parser); exp_loc = c_parser_peek_token (parser)->location; op = c_parser_cast_expression (parser, NULL); - - op = default_function_array_read_conversion (exp_loc, op); + if ((VAR_P (op.value) || TREE_CODE (op.value) == PARM_DECL) + && !DECL_READ_P (op.value) + && (VAR_P (op.value) ? warn_unused_but_set_variable + : warn_unused_but_set_parameter) > 1) + { + op = default_function_array_read_conversion (exp_loc, op); + DECL_READ_P (op.value) = 0; + } + else + op = default_function_array_read_conversion (exp_loc, op); return parser_build_unary_op (op_loc, PREINCREMENT_EXPR, op); case CPP_MINUS_MINUS: c_parser_consume_token (parser); exp_loc = c_parser_peek_token (parser)->location; op = c_parser_cast_expression (parser, NULL); - - op = default_function_array_read_conversion (exp_loc, op); + if ((VAR_P (op.value) || TREE_CODE (op.value) == PARM_DECL) + && !DECL_READ_P (op.value) + && (VAR_P (op.value) ? warn_unused_but_set_variable + : warn_unused_but_set_parameter) > 1) + { + op = default_function_array_read_conversion (exp_loc, op); + DECL_READ_P (op.value) = 0; + } + else + op = default_function_array_read_conversion (exp_loc, op); return parser_build_unary_op (op_loc, PREDECREMENT_EXPR, op); case CPP_AND: c_parser_consume_token (parser); @@ -10572,6 +10640,8 @@ c_parser_unary_expression (c_parser *parser) case CPP_KEYWORD: switch (c_parser_peek_token (parser)->keyword) { + case RID_COUNTOF: + return c_parser_countof_expression (parser); case RID_SIZEOF: return c_parser_sizeof_expression (parser); case RID_ALIGNOF: @@ -10610,22 +10680,46 @@ c_parser_unary_expression (c_parser *parser) /* Parse a sizeof expression. */ -static struct c_expr +static inline struct c_expr c_parser_sizeof_expression (c_parser *parser) { + return c_parser_sizeof_or_countof_expression (parser, RID_SIZEOF); +} + +/* Parse a _Countof expression. */ + +static inline struct c_expr +c_parser_countof_expression (c_parser *parser) +{ + return c_parser_sizeof_or_countof_expression (parser, RID_COUNTOF); +} + +/* Parse a sizeof or _Countof expression. */ + +static struct c_expr +c_parser_sizeof_or_countof_expression (c_parser *parser, enum rid rid) +{ + const char *op_name = (rid == RID_COUNTOF) ? "_Countof" : "sizeof"; struct c_expr expr; struct c_expr result; location_t expr_loc; - gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF)); + gcc_assert (c_parser_next_token_is_keyword (parser, rid)); location_t start; location_t finish = UNKNOWN_LOCATION; start = c_parser_peek_token (parser)->location; + if (rid == RID_COUNTOF) + pedwarn_c23 (start, OPT_Wpedantic, + "ISO C does not support %qs before C2Y", op_name); + c_parser_consume_token (parser); c_inhibit_evaluation_warnings++; - in_sizeof++; + if (rid == RID_COUNTOF) + in_countof++; + else + in_sizeof++; if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) && c_token_starts_compound_literal (c_parser_peek_2nd_token (parser))) { @@ -10646,7 +10740,7 @@ c_parser_sizeof_expression (c_parser *parser) for parsing error; the parsing of the expression could have called record_maybe_used_decl. */ expr.set_error (); - goto sizeof_expr; + goto Xof_expr; } if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) { @@ -10654,31 +10748,45 @@ c_parser_sizeof_expression (c_parser *parser) type_name, expr_loc); finish = expr.get_finish (); - goto sizeof_expr; + goto Xof_expr; } /* sizeof ( type-name ). */ if (scspecs) - error_at (expr_loc, "storage class specifier in %<sizeof%>"); + error_at (expr_loc, "storage class specifier in %qs", op_name); if (type_name->specs->alignas_p) error_at (type_name->specs->locations[cdw_alignas], - "alignment specified for type name in %<sizeof%>"); + "alignment specified for type name in %qs", op_name); c_inhibit_evaluation_warnings--; - in_sizeof--; - result = c_expr_sizeof_type (expr_loc, type_name); + if (rid == RID_COUNTOF) + { + in_countof--; + result = c_expr_countof_type (expr_loc, type_name); + } + else + { + in_sizeof--; + result = c_expr_sizeof_type (expr_loc, type_name); + } } else { expr_loc = c_parser_peek_token (parser)->location; expr = c_parser_unary_expression (parser); finish = expr.get_finish (); - sizeof_expr: + Xof_expr: c_inhibit_evaluation_warnings--; - in_sizeof--; + if (rid == RID_COUNTOF) + in_countof--; + else + in_sizeof--; mark_exp_read (expr.value); if (TREE_CODE (expr.value) == COMPONENT_REF && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1))) - error_at (expr_loc, "%<sizeof%> applied to a bit-field"); - result = c_expr_sizeof_expr (expr_loc, expr); + error_at (expr_loc, "%qs applied to a bit-field", op_name); + if (rid == RID_COUNTOF) + result = c_expr_countof_expr (expr_loc, expr); + else + result = c_expr_sizeof_expr (expr_loc, expr); } if (finish == UNKNOWN_LOCATION) finish = start; @@ -11054,8 +11162,14 @@ c_parser_generic_selection (c_parser *parser) "ISO C does not support use of type name as %<_Generic%> " "controlling operand before C2Y"); struct c_type_name *type = c_parser_type_name (parser); - selector_type = groktypename (type, NULL, NULL); + if (type) + selector_type = groktypename (type, NULL, NULL); c_inhibit_evaluation_warnings--; + if (!type) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + return error_expr; + } } else { @@ -13835,7 +13949,17 @@ c_parser_postfix_expression_after_primary (c_parser *parser, start = expr.get_start (); finish = c_parser_peek_token (parser)->get_finish (); c_parser_consume_token (parser); - expr = default_function_array_read_conversion (expr_loc, expr); + if ((VAR_P (expr.value) || TREE_CODE (expr.value) == PARM_DECL) + && !DECL_READ_P (expr.value) + && (VAR_P (expr.value) ? warn_unused_but_set_variable + : warn_unused_but_set_parameter) > 1 + && TREE_CODE (TREE_TYPE (expr.value)) != ARRAY_TYPE) + { + expr = default_function_array_read_conversion (expr_loc, expr); + DECL_READ_P (expr.value) = 0; + } + else + expr = default_function_array_read_conversion (expr_loc, expr); expr.value = build_unary_op (op_loc, POSTINCREMENT_EXPR, expr.value, false); set_c_expr_source_range (&expr, start, finish); @@ -13847,7 +13971,17 @@ c_parser_postfix_expression_after_primary (c_parser *parser, start = expr.get_start (); finish = c_parser_peek_token (parser)->get_finish (); c_parser_consume_token (parser); - expr = default_function_array_read_conversion (expr_loc, expr); + if ((VAR_P (expr.value) || TREE_CODE (expr.value) == PARM_DECL) + && !DECL_READ_P (expr.value) + && (VAR_P (expr.value) ? warn_unused_but_set_variable + : warn_unused_but_set_parameter) > 1 + && TREE_CODE (TREE_TYPE (expr.value)) != ARRAY_TYPE) + { + expr = default_function_array_read_conversion (expr_loc, expr); + DECL_READ_P (expr.value) = 0; + } + else + expr = default_function_array_read_conversion (expr_loc, expr); expr.value = build_unary_op (op_loc, POSTDECREMENT_EXPR, expr.value, false); set_c_expr_source_range (&expr, start, finish); @@ -16525,7 +16659,7 @@ c_parser_omp_variable_list (c_parser *parser, || CONVERT_EXPR_P (decl)) decl = TREE_OPERAND (decl, 0); - tree u = build_omp_clause (clause_loc, kind); + tree u = build_omp_clause (loc, kind); OMP_CLAUSE_DECL (u) = decl; OMP_CLAUSE_CHAIN (u) = list; list = u; @@ -19938,14 +20072,14 @@ c_parser_omp_clause_doacross (c_parser *parser, tree list) map ( [map-type-modifier[,] ...] map-kind: variable-list ) map-type-modifier: - always | close */ + always | close | present | iterator (iterators-definition) */ static tree -c_parser_omp_clause_map (c_parser *parser, tree list) +c_parser_omp_clause_map (c_parser *parser, tree list, bool declare_mapper_p) { location_t clause_loc = c_parser_peek_token (parser)->location; - enum gomp_map_kind kind = GOMP_MAP_TOFROM; tree nl, c; + enum gomp_map_kind kind = declare_mapper_p ? GOMP_MAP_UNSET : GOMP_MAP_TOFROM; matching_parens parens; if (!parens.require_open (parser)) @@ -19953,22 +20087,57 @@ c_parser_omp_clause_map (c_parser *parser, tree list) int pos = 1; int map_kind_pos = 0; - while (c_parser_peek_nth_token_raw (parser, pos)->type == CPP_NAME) + int iterator_length = 0; + for (;;) { - if (c_parser_peek_nth_token_raw (parser, pos + 1)->type == CPP_COLON) + c_token *tok = c_parser_peek_nth_token_raw (parser, pos); + if (tok->type != CPP_NAME) + break; + + const char *p = IDENTIFIER_POINTER (tok->value); + c_token *next_tok = c_parser_peek_nth_token_raw (parser, pos + 1); + if (strcmp (p, "iterator") == 0 && next_tok->type == CPP_OPEN_PAREN) + { + unsigned n = pos + 2; + if (c_parser_check_balanced_raw_token_sequence (parser, &n) + && c_parser_peek_nth_token_raw (parser, n)->type + == CPP_CLOSE_PAREN) + { + iterator_length = n - pos + 1; + pos = n; + next_tok = c_parser_peek_nth_token_raw (parser, pos + 1); + } + } + + if (next_tok->type == CPP_COLON) { map_kind_pos = pos; break; } - if (c_parser_peek_nth_token_raw (parser, pos + 1)->type == CPP_COMMA) + if (next_tok->type == CPP_COMMA) pos++; + else if (c_parser_peek_nth_token_raw (parser, pos + 1)->type + == CPP_OPEN_PAREN) + { + unsigned int npos = pos + 2; + if (c_parser_check_balanced_raw_token_sequence (parser, &npos) + && (c_parser_peek_nth_token_raw (parser, npos)->type + == CPP_CLOSE_PAREN) + && (c_parser_peek_nth_token_raw (parser, npos + 1)->type + == CPP_COMMA)) + pos = npos + 1; + } + pos++; } int always_modifier = 0; int close_modifier = 0; int present_modifier = 0; + int mapper_modifier = 0; + tree mapper_name = NULL_TREE; + tree iterators = NULL_TREE; for (int pos = 1; pos < map_kind_pos; ++pos) { c_token *tok = c_parser_peek_token (parser); @@ -19989,6 +20158,7 @@ c_parser_omp_clause_map (c_parser *parser, tree list) return list; } always_modifier++; + c_parser_consume_token (parser); } else if (strcmp ("close", p) == 0) { @@ -19999,6 +20169,77 @@ c_parser_omp_clause_map (c_parser *parser, tree list) return list; } close_modifier++; + c_parser_consume_token (parser); + } + else if (strcmp ("iterator", p) == 0) + { + if (iterators) + { + c_parser_error (parser, "too many %<iterator%> modifiers"); + parens.skip_until_found_close (parser); + return list; + } + iterators = c_parser_omp_iterators (parser); + pos += iterator_length - 1; + } + else if (strcmp ("mapper", p) == 0) + { + c_parser_consume_token (parser); + + matching_parens mparens; + if (mparens.require_open (parser)) + { + if (mapper_modifier) + { + c_parser_error (parser, "too many %<mapper%> modifiers"); + /* Assume it's a well-formed mapper modifier, even if it + seems to be in the wrong place. */ + c_parser_consume_token (parser); + mparens.require_close (parser); + parens.skip_until_found_close (parser); + return list; + } + + tok = c_parser_peek_token (parser); + + switch (tok->type) + { + case CPP_NAME: + { + mapper_name = tok->value; + c_parser_consume_token (parser); + if (declare_mapper_p) + { + error_at (tok->location, + "in %<declare mapper%> directives, parameter " + "to %<mapper%> modifier must be %<default%>"); + } + } + break; + + case CPP_KEYWORD: + if (tok->keyword == RID_DEFAULT) + { + c_parser_consume_token (parser); + break; + } + /* Fallthrough. */ + + default: + error_at (tok->location, + "expected identifier or %<default%>"); + return list; + } + + if (!mparens.require_close (parser)) + { + parens.skip_until_found_close (parser); + return list; + } + + mapper_modifier++; + pos += 3; + } } else if (strcmp ("present", p) == 0) { @@ -20009,16 +20250,16 @@ c_parser_omp_clause_map (c_parser *parser, tree list) return list; } present_modifier++; + c_parser_consume_token (parser); } else { c_parser_error (parser, "%<map%> clause with map-type modifier other " - "than %<always%>, %<close%> or %<present%>"); + "than %<always%>, %<close%>, %<iterator%>, " + "%<mapper%> or %<present%>"); parens.skip_until_found_close (parser); return list; } - - c_parser_consume_token (parser); } if (c_parser_next_token_is (parser, CPP_NAME) @@ -20062,8 +20303,40 @@ c_parser_omp_clause_map (c_parser *parser, tree list) nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_MAP, list, true); + tree last_new = NULL_TREE; + + if (iterators) + { + tree block = pop_scope (); + if (iterators == error_mark_node) + iterators = NULL_TREE; + else + TREE_VEC_ELT (iterators, 5) = block; + } + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_SET_MAP_KIND (c, kind); + { + OMP_CLAUSE_SET_MAP_KIND (c, kind); + OMP_CLAUSE_ITERATORS (c) = iterators; + last_new = c; + } + + if (mapper_name) + { + tree name = build_omp_clause (input_location, OMP_CLAUSE_MAP); + OMP_CLAUSE_SET_MAP_KIND (name, GOMP_MAP_PUSH_MAPPER_NAME); + OMP_CLAUSE_DECL (name) = mapper_name; + OMP_CLAUSE_CHAIN (name) = nl; + nl = name; + + gcc_assert (last_new); + + name = build_omp_clause (input_location, OMP_CLAUSE_MAP); + OMP_CLAUSE_SET_MAP_KIND (name, GOMP_MAP_POP_MAPPER_NAME); + OMP_CLAUSE_DECL (name) = null_pointer_node; + OMP_CLAUSE_CHAIN (name) = OMP_CLAUSE_CHAIN (last_new); + OMP_CLAUSE_CHAIN (last_new) = name; + } parens.skip_until_found_close (parser); return nl; @@ -20303,8 +20576,11 @@ c_parser_omp_clause_device_type (c_parser *parser, tree list) to ( variable-list ) OpenMP 5.1: - from ( [present :] variable-list ) - to ( [present :] variable-list ) */ + from ( [motion-modifier[,] [motion-modifier[,]...]:] variable-list ) + to ( [motion-modifier[,] [motion-modifier[,]...]:] variable-list ) + + motion-modifier: + present | iterator (iterators-definition) */ static tree c_parser_omp_clause_from_to (c_parser *parser, enum omp_clause_code kind, @@ -20315,18 +20591,85 @@ c_parser_omp_clause_from_to (c_parser *parser, enum omp_clause_code kind, if (!parens.require_open (parser)) return list; + int pos = 1, colon_pos = 0; + int iterator_length = 0; + + while (c_parser_peek_nth_token_raw (parser, pos)->type == CPP_NAME) + { + const char *identifier = + IDENTIFIER_POINTER (c_parser_peek_nth_token_raw (parser, pos)->value); + if (c_parser_peek_nth_token_raw (parser, pos + 1)->type + == CPP_OPEN_PAREN) + { + unsigned int npos = pos + 2; + if (c_parser_check_balanced_raw_token_sequence (parser, &npos) + && (c_parser_peek_nth_token_raw (parser, npos)->type + == CPP_CLOSE_PAREN)) + { + if (strcmp (identifier, "iterator") == 0) + iterator_length = npos - pos + 1; + pos = npos; + } + } + if (c_parser_peek_nth_token_raw (parser, pos + 1)->type == CPP_COMMA) + pos += 2; + else + pos++; + if (c_parser_peek_nth_token_raw (parser, pos)->type == CPP_COLON) + { + colon_pos = pos; + break; + } + } + bool present = false; - c_token *token = c_parser_peek_token (parser); + tree iterators = NULL_TREE; - if (token->type == CPP_NAME - && strcmp (IDENTIFIER_POINTER (token->value), "present") == 0 - && c_parser_peek_2nd_token (parser)->type == CPP_COLON) + for (int pos = 1; pos < colon_pos; ++pos) { - present = true; - c_parser_consume_token (parser); - c_parser_consume_token (parser); + c_token *token = c_parser_peek_token (parser); + if (token->type == CPP_COMMA) + { + c_parser_consume_token (parser); + continue; + } + const char *p = IDENTIFIER_POINTER (token->value); + if (strcmp ("present", p) == 0) + { + if (present) + { + c_parser_error (parser, "too many %<present%> modifiers"); + parens.skip_until_found_close (parser); + return list; + } + present = true; + c_parser_consume_token (parser); + } + else if (strcmp ("iterator", p) == 0) + { + if (iterators) + { + c_parser_error (parser, "too many %<iterator%> modifiers"); + parens.skip_until_found_close (parser); + return list; + } + iterators = c_parser_omp_iterators (parser); + pos += iterator_length - 1; + } + else + { + error_at (token->location, + "%qs clause with modifier other than %<iterator%> or " + "%<present%>", + kind == OMP_CLAUSE_TO ? "to" : "from"); + parens.skip_until_found_close (parser); + return list; + } } + if (colon_pos) + c_parser_require (parser, CPP_COLON, "expected %<:%>"); + tree nl = c_parser_omp_variable_list (parser, loc, kind, list); parens.skip_until_found_close (parser); @@ -20334,6 +20677,19 @@ c_parser_omp_clause_from_to (c_parser *parser, enum omp_clause_code kind, for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) OMP_CLAUSE_MOTION_PRESENT (c) = 1; + if (iterators) + { + tree block = pop_scope (); + if (iterators == error_mark_node) + iterators = NULL_TREE; + else + TREE_VEC_ELT (iterators, 5) = block; + } + + if (iterators) + for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_ITERATORS (c) = iterators; + return nl; } @@ -21432,7 +21788,7 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, c_name = "interop"; break; case PRAGMA_OMP_CLAUSE_MAP: - clauses = c_parser_omp_clause_map (parser, clauses); + clauses = c_parser_omp_clause_map (parser, clauses, false); c_name = "map"; break; case PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR: @@ -22306,7 +22662,8 @@ c_parser_oacc_update (c_parser *parser) */ #define OACC_WAIT_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) ) + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) ) static tree c_parser_oacc_wait (location_t loc, c_parser *parser, char *p_name) @@ -26251,7 +26608,7 @@ c_parser_omp_target (c_parser *parser, enum pragma_context context, bool *if_p) { location_t loc = c_parser_peek_token (parser)->location; c_parser_consume_pragma (parser); - tree *pc = NULL, stmt, block; + tree *pc = NULL, stmt, block, body, clauses; if (context != pragma_stmt && context != pragma_compound) { @@ -26406,10 +26763,9 @@ c_parser_omp_target (c_parser *parser, enum pragma_context context, bool *if_p) stmt = make_node (OMP_TARGET); TREE_TYPE (stmt) = void_type_node; - OMP_TARGET_CLAUSES (stmt) - = c_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK, - "#pragma omp target", false); - for (tree c = OMP_TARGET_CLAUSES (stmt); c; c = OMP_CLAUSE_CHAIN (c)) + clauses = c_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK, + "#pragma omp target", false); + for (tree c = clauses; 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); @@ -26418,14 +26774,19 @@ c_parser_omp_target (c_parser *parser, enum pragma_context context, bool *if_p) 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); + clauses = c_omp_instantiate_mappers (clauses); + clauses = c_finish_omp_clauses (clauses, C_ORT_OMP_TARGET); + c_omp_adjust_map_clauses (clauses, true); - pc = &OMP_TARGET_CLAUSES (stmt); keep_next_level (); block = c_begin_compound_stmt (true); - add_stmt (c_parser_omp_structured_block (parser, if_p)); + body = c_parser_omp_structured_block (parser, if_p); + + c_omp_scan_mapper_bindings (loc, &clauses, body); + + add_stmt (body); + OMP_TARGET_CLAUSES (stmt) = clauses; + pc = &OMP_TARGET_CLAUSES (stmt); OMP_TARGET_BODY (stmt) = c_end_compound_stmt (loc, block, true); SET_EXPR_LOCATION (stmt, loc); @@ -26773,20 +27134,31 @@ c_parser_omp_context_selector (c_parser *parser, enum omp_tss_code set, break; case OMP_TRAIT_PROPERTY_DEV_NUM_EXPR: case OMP_TRAIT_PROPERTY_BOOL_EXPR: - t = c_parser_expr_no_commas (parser, NULL).value; - if (t != error_mark_node) + { + c_expr texpr = c_parser_expr_no_commas (parser, NULL); + texpr = convert_lvalue_to_rvalue (token->location, texpr, + true, true); + t = texpr.value; + } + if (t == error_mark_node) + return error_mark_node; + mark_exp_read (t); + if (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR) { - mark_exp_read (t); - t = c_fully_fold (t, false, NULL); - if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) - error_at (token->location, - "property must be integer expression"); - else - properties = make_trait_property (NULL_TREE, t, - properties); + t = c_objc_common_truthvalue_conversion (token->location, + t, + boolean_type_node); + if (t == error_mark_node) + return error_mark_node; } - else - return error_mark_node; + else if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error_at (token->location, + "property must be integer expression"); + return error_mark_node; + } + t = c_fully_fold (t, false, NULL); + properties = make_trait_property (NULL_TREE, t, properties); break; case OMP_TRAIT_PROPERTY_CLAUSE_LIST: if (sel == OMP_TRAIT_CONSTRUCT_SIMD) @@ -26888,11 +27260,14 @@ c_parser_omp_context_selector_specification (c_parser *parser, tree parms) tree selectors = c_parser_omp_context_selector (parser, set, parms); if (selectors == error_mark_node) - ret = error_mark_node; + { + c_parser_skip_to_closing_brace (parser); + ret = error_mark_node; + } else if (ret != error_mark_node) ret = make_trait_set_selector (set, selectors, ret); - braces.skip_until_found_close (parser); + braces.require_close (parser); if (c_parser_next_token_is (parser, CPP_COMMA)) c_parser_consume_token (parser); @@ -27797,6 +28172,151 @@ c_parser_omp_end (c_parser *parser) } } +/* OpenMP 5.0 + #pragma omp declare mapper ([mapper-identifier :] type var) \ + [clause [ [,] clause ] ... ] new-line */ + +static void +c_parser_omp_declare_mapper (c_parser *parser, enum pragma_context context) +{ + tree type, mapper_name = NULL_TREE, var = NULL_TREE, stmt, stmtlist; + tree maplist = NULL_TREE, mapper_id, mapper_decl, t; + c_token *token; + + if (context == pragma_struct || context == pragma_param) + { + error ("%<#pragma omp declare mapper%> not at file or block scope"); + goto fail; + } + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + goto fail; + + token = c_parser_peek_token (parser); + + if (c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + switch (token->type) + { + case CPP_NAME: + mapper_name = token->value; + c_parser_consume_token (parser); + break; + case CPP_KEYWORD: + if (token->keyword == RID_DEFAULT) + { + mapper_name = NULL_TREE; + c_parser_consume_token (parser); + break; + } + /* Fallthrough. */ + default: + error_at (token->location, "expected identifier or %<default%>"); + c_parser_skip_to_pragma_eol (parser, false); + return; + } + + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + goto fail; + } + + mapper_id = c_omp_mapper_id (mapper_name); + mapper_decl = c_omp_mapper_decl (mapper_id); + + { + location_t loc = c_parser_peek_token (parser)->location; + struct c_type_name *ctype = c_parser_type_name (parser); + type = groktypename (ctype, NULL, NULL); + if (type == error_mark_node) + goto fail; + if (!RECORD_OR_UNION_TYPE_P (type)) + { + error_at (loc, "%qT is not a struct or union type in " + "%<#pragma omp declare mapper%>", type); + c_parser_skip_to_pragma_eol (parser, false); + return; + } + for (tree t = DECL_INITIAL (mapper_decl); t; t = TREE_CHAIN (t)) + if (comptypes (TREE_PURPOSE (t), type)) + { + error_at (loc, "redeclaration of %qs %<#pragma omp declare " + "mapper%> for type %qT", IDENTIFIER_POINTER (mapper_id) + + sizeof ("omp declare mapper ") - 1, + type); + tree prevmapper = TREE_VALUE (t); + /* Hmm, this location might not be very accurate. */ + location_t ploc + = DECL_SOURCE_LOCATION (OMP_DECLARE_MAPPER_DECL (prevmapper)); + inform (ploc, "%<#pragma omp declare mapper%> " + "previously declared here"); + c_parser_skip_to_pragma_eol (parser, false); + return; + } + } + + token = c_parser_peek_token (parser); + if (token->type == CPP_NAME) + { + var = build_decl (token->location, VAR_DECL, token->value, type); + c_parser_consume_token (parser); + DECL_ARTIFICIAL (var) = 1; + } + else + { + error_at (token->location, "expected identifier"); + goto fail; + } + + if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + goto fail; + + push_scope (); + stmtlist = push_stmt_list (); + pushdecl (var); + DECL_CONTEXT (var) = current_function_decl; + + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + { + location_t here; + pragma_omp_clause c_kind; + here = c_parser_peek_token (parser)->location; + c_kind = c_parser_omp_clause_name (parser); + if (c_kind != PRAGMA_OMP_CLAUSE_MAP) + { + error_at (here, "unexpected clause"); + goto fail; + } + maplist = c_parser_omp_clause_map (parser, maplist, true); + } + + if (maplist == NULL_TREE) + { + error_at (input_location, "missing %<map%> clause"); + goto fail; + } + + stmt = make_node (OMP_DECLARE_MAPPER); + TREE_TYPE (stmt) = type; + OMP_DECLARE_MAPPER_ID (stmt) = mapper_name; + OMP_DECLARE_MAPPER_DECL (stmt) = var; + OMP_DECLARE_MAPPER_CLAUSES (stmt) = maplist; + + add_stmt (stmt); + + pop_stmt_list (stmtlist); + pop_scope (); + + c_parser_skip_to_pragma_eol (parser); + + t = tree_cons (type, stmt, DECL_INITIAL (mapper_decl)); + DECL_INITIAL (mapper_decl) = t; + + return; + + fail: + c_parser_skip_to_pragma_eol (parser); +} + /* OpenMP 4.0 #pragma omp declare reduction (reduction-id : typename-list : expression) \ initializer-clause[opt] new-line @@ -27923,8 +28443,8 @@ c_parser_omp_declare_reduction (c_parser *parser, enum pragma_context context) location_t ploc = DECL_SOURCE_LOCATION (TREE_VEC_ELT (TREE_VALUE (t), 0)); - error_at (ploc, "previous %<#pragma omp declare " - "reduction%>"); + inform (ploc, "%<#pragma omp declare reduction%> " + "previously declared here"); break; } if (t == NULL_TREE) @@ -28188,6 +28708,12 @@ c_parser_omp_declare (c_parser *parser, enum pragma_context context) c_parser_omp_declare_reduction (parser, context); return false; } + if (strcmp (p, "mapper") == 0) + { + c_parser_consume_token (parser); + c_parser_omp_declare_mapper (parser, context); + return false; + } if (!flag_openmp) /* flag_openmp_simd */ { c_parser_skip_to_pragma_eol (parser, false); @@ -28761,11 +29287,14 @@ c_parser_omp_error (c_parser *parser, enum pragma_context context) if (msg == NULL) msg = _("<message unknown at compile time>"); } + const enum diagnostics::kind diag_kind = (severity_fatal + ? diagnostics::kind::error + : diagnostics::kind::warning); if (msg) - emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, + emit_diagnostic (diag_kind, loc, 0, "%<pragma omp error%> encountered: %s", msg); else - emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, + emit_diagnostic (diag_kind, loc, 0, "%<pragma omp error%> encountered"); return false; } @@ -29097,7 +29626,6 @@ c_parser_omp_metadirective (c_parser *parser, bool *if_p) { error_at (match_loc, "too many %<otherwise%> or %<default%> " "clauses in %<metadirective%>"); - c_parser_skip_to_end_of_block_or_statement (parser, true); goto error; } default_seen = true; @@ -29106,14 +29634,12 @@ c_parser_omp_metadirective (c_parser *parser, bool *if_p) { error_at (match_loc, "%<otherwise%> or %<default%> clause " "must appear last in %<metadirective%>"); - c_parser_skip_to_end_of_block_or_statement (parser, true); goto error; } if (!default_p && strcmp (p, "when") != 0) { error_at (match_loc, "%qs is not valid for %qs", p, "metadirective"); - c_parser_skip_to_end_of_block_or_statement (parser, true); goto error; } @@ -29181,7 +29707,6 @@ c_parser_omp_metadirective (c_parser *parser, bool *if_p) if (i == 0) { error_at (loc, "expected directive name"); - c_parser_skip_to_end_of_block_or_statement (parser, true); goto error; } @@ -29249,7 +29774,10 @@ c_parser_omp_metadirective (c_parser *parser, bool *if_p) goto add; case CPP_CLOSE_PAREN: if (nesting_depth-- == 0) - break; + { + c_parser_consume_token (parser); + break; + } goto add; default: add: @@ -29261,8 +29789,6 @@ c_parser_omp_metadirective (c_parser *parser, bool *if_p) break; } - c_parser_consume_token (parser); - if (!skip) { c_token eol_token; @@ -29389,9 +29915,9 @@ c_parser_omp_metadirective (c_parser *parser, bool *if_p) return; error: + /* Skip the metadirective pragma. Do not skip the metadirective body. */ if (parser->in_pragma) - c_parser_skip_to_pragma_eol (parser); - c_parser_skip_to_end_of_block_or_statement (parser, true); + c_parser_skip_to_pragma_eol (parser, false); } /* Main entry point to parsing most OpenMP pragmas. */ diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 2098120..dba94ab 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -163,7 +163,8 @@ along with GCC; see the file COPYING3. If not see (TREE_CODE (TYPE) == BOOLEAN_TYPE \ || (TREE_CODE (TYPE) == ENUMERAL_TYPE \ && ENUM_UNDERLYING_TYPE (TYPE) != NULL_TREE \ - && TREE_CODE (ENUM_UNDERLYING_TYPE (TYPE)) == BOOLEAN_TYPE)) + && (TREE_CODE (ENUM_UNDERLYING_TYPE (TYPE)) == BOOLEAN_TYPE \ + || c_hardbool_type_attr (TYPE)))) /* Record parser information about an expression that is irrelevant for code generation alongside a tree representing its value. */ @@ -757,7 +758,7 @@ extern tree c_finish_bc_name (location_t, tree, bool); extern bool c_objc_common_init (void); extern bool c_missing_noreturn_ok_p (tree); extern bool c_warn_unused_global_decl (const_tree); -extern void c_initialize_diagnostics (diagnostic_context *); +extern void c_initialize_diagnostics (diagnostics::context *); extern bool c_var_mod_p (tree x, tree fn); extern alias_set_type c_get_alias_set (tree); extern int c_type_dwarf_attribute (const_tree, int); @@ -765,6 +766,7 @@ extern int c_type_dwarf_attribute (const_tree, int); /* in c-typeck.cc */ extern int in_alignof; extern int in_sizeof; +extern int in_countof; extern int in_typeof; extern bool c_in_omp_for; extern bool c_omp_array_section_p; @@ -827,6 +829,9 @@ extern tree build_external_ref (location_t, tree, bool, tree *); extern void pop_maybe_used (bool); extern struct c_expr c_expr_sizeof_expr (location_t, struct c_expr); extern struct c_expr c_expr_sizeof_type (location_t, struct c_type_name *); +extern struct c_expr c_expr_countof_expr (location_t, struct c_expr); +extern struct c_expr c_expr_countof_type (location_t loc, + struct c_type_name *); extern struct c_expr parser_build_unary_op (location_t, enum tree_code, struct c_expr); extern struct c_expr parser_build_binary_op (location_t, @@ -884,6 +889,10 @@ extern tree c_finish_omp_task (location_t, tree, tree); extern void c_finish_omp_cancel (location_t, tree); extern void c_finish_omp_cancellation_point (location_t, tree); extern tree c_finish_omp_clauses (tree, enum c_omp_region_type); +extern tree c_omp_finish_mapper_clauses (tree); +extern tree c_omp_mapper_lookup (tree, tree); +extern tree c_omp_extract_mapper_directive (tree); +extern tree c_omp_map_array_section (location_t, tree); 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); @@ -942,19 +951,23 @@ extern tree c_omp_reduction_id (enum tree_code, tree); extern tree c_omp_reduction_decl (tree); extern tree c_omp_reduction_lookup (tree, tree); extern tree c_check_omp_declare_reduction_r (tree *, int *, void *); +extern tree c_omp_mapper_id (tree); +extern tree c_omp_mapper_decl (tree); +extern void c_omp_scan_mapper_bindings (location_t, tree *, tree); +extern tree c_omp_instantiate_mappers (tree); extern bool c_check_in_current_scope (tree); extern void c_pushtag (location_t, tree, tree); extern void c_bind (location_t, tree, bool); extern bool tag_exists_p (enum tree_code, tree); /* In c-errors.cc */ -extern bool pedwarn_c90 (location_t, diagnostic_option_id, const char *, ...) +extern bool pedwarn_c90 (location_t, diagnostics::option_id, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4); -extern bool pedwarn_c99 (location_t, diagnostic_option_id, const char *, ...) +extern bool pedwarn_c99 (location_t, diagnostics::option_id, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4); -extern bool pedwarn_c11 (location_t, diagnostic_option_id, const char *, ...) +extern bool pedwarn_c11 (location_t, diagnostics::option_id, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4); -extern bool pedwarn_c23 (location_t, diagnostic_option_id, const char *, ...) +extern bool pedwarn_c23 (location_t, diagnostics::option_id, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4); extern void add_note_about_new_keyword (location_t loc, tree keyword_id); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index d94ecb5..7a95f72 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -72,6 +72,9 @@ int in_alignof; /* The level of nesting inside "sizeof". */ int in_sizeof; +/* The level of nesting inside "countof". */ +int in_countof; + /* The level of nesting inside "typeof". */ int in_typeof; @@ -133,6 +136,7 @@ static int lvalue_or_else (location_t, const_tree, enum lvalue_use); static void record_maybe_used_decl (tree); static bool comptypes_internal (const_tree, const_tree, struct comptypes_data *data); +static bool comptypes_check_for_composite (tree t1, tree t2); /* Return true if EXP is a null pointer constant, false otherwise. */ @@ -610,6 +614,17 @@ c_type_tag (const_tree t) return name; } +/* Remove qualifiers but not atomic. For arrays remove qualifiers + on the element type but also do not remove atomic. */ +static tree +remove_qualifiers (tree t) +{ + if (!t || t == error_mark_node) + return t; + return TYPE_ATOMIC (strip_array_types (t)) + ? c_build_qualified_type (TYPE_MAIN_VARIANT (t), TYPE_QUAL_ATOMIC) + : TYPE_MAIN_VARIANT (t); +} /* Return the composite type of two compatible types. @@ -626,7 +641,8 @@ struct composite_cache { }; tree -composite_type_internal (tree t1, tree t2, struct composite_cache* cache) +composite_type_internal (tree t1, tree t2, tree cond, + struct composite_cache* cache) { enum tree_code code1; enum tree_code code2; @@ -671,8 +687,8 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) { tree pointed_to_1 = TREE_TYPE (t1); tree pointed_to_2 = TREE_TYPE (t2); - tree target = composite_type_internal (pointed_to_1, - pointed_to_2, cache); + tree target = composite_type_internal (pointed_to_1, pointed_to_2, + cond, cache); t1 = c_build_pointer_type_for_mode (target, TYPE_MODE (t1), false); t1 = c_build_type_attribute_variant (t1, attributes); return qualify_type (t1, t2); @@ -680,25 +696,20 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) case ARRAY_TYPE: { - tree elt = composite_type_internal (TREE_TYPE (t1), TREE_TYPE (t2), - cache); - int quals; - tree unqual_elt; tree d1 = TYPE_DOMAIN (t1); tree d2 = TYPE_DOMAIN (t2); - bool d1_variable, d2_variable; - bool d1_zero, d2_zero; - bool t1_complete, t2_complete; /* We should not have any type quals on arrays at all. */ gcc_assert (!TYPE_QUALS_NO_ADDR_SPACE (t1) && !TYPE_QUALS_NO_ADDR_SPACE (t2)); - t1_complete = COMPLETE_TYPE_P (t1); - t2_complete = COMPLETE_TYPE_P (t2); + bool t1_complete = COMPLETE_TYPE_P (t1); + bool t2_complete = COMPLETE_TYPE_P (t2); + + bool d1_zero = d1 == NULL_TREE || !TYPE_MAX_VALUE (d1); + bool d2_zero = d2 == NULL_TREE || !TYPE_MAX_VALUE (d2); - d1_zero = d1 == NULL_TREE || !TYPE_MAX_VALUE (d1); - d2_zero = d2 == NULL_TREE || !TYPE_MAX_VALUE (d2); + bool d1_variable, d2_variable; d1_variable = (!d1_zero && (TREE_CODE (TYPE_MIN_VALUE (d1)) != INTEGER_CST @@ -707,10 +718,8 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) && (TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST || TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST)); - bool use1 = TYPE_DOMAIN (t1) - && (d2_variable || d2_zero || !d1_variable); - bool use2 = TYPE_DOMAIN (t2) - && (d1_variable || d1_zero || !d2_variable); + bool use1 = d1 && (d2_variable || d2_zero || !d1_variable); + bool use2 = d2 && (d1_variable || d1_zero || !d2_variable); /* If the first is an unspecified size pick the other one. */ if (d2_variable && c_type_unspecified_p (t1)) @@ -719,25 +728,53 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) use1 = false; } - /* Save space: see if the result is identical to one of the args. */ - if (elt == TREE_TYPE (t1) && use1) - return c_build_type_attribute_variant (t1, attributes); - if (elt == TREE_TYPE (t2) && use2) - return c_build_type_attribute_variant (t2, attributes); + /* If both are VLAs but not unspecified and we are in the + conditional operator, we create a conditional to select + the size of the active branch. */ + bool use0 = cond && d1_variable && !c_type_unspecified_p (t1) + && d2_variable && !c_type_unspecified_p (t2); - if (elt == TREE_TYPE (t1) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1)) - return c_build_type_attribute_variant (t1, attributes); - if (elt == TREE_TYPE (t2) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1)) - return c_build_type_attribute_variant (t2, attributes); + tree td; + tree elt = composite_type_internal (TREE_TYPE (t1), TREE_TYPE (t2), + cond, cache); + + if (!use0) + { + /* Save space: see if the result is identical to one of the args. */ + if (elt == TREE_TYPE (t1) && use1) + return c_build_type_attribute_variant (t1, attributes); + if (elt == TREE_TYPE (t2) && use2) + return c_build_type_attribute_variant (t2, attributes); + + if (elt == TREE_TYPE (t1) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1)) + return c_build_type_attribute_variant (t1, attributes); + if (elt == TREE_TYPE (t2) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1)) + return c_build_type_attribute_variant (t2, attributes); + + td = TYPE_DOMAIN (use1 ? t1 : t2); + } + else + { + /* Not used in C. */ + gcc_assert (size_zero_node == TYPE_MIN_VALUE (d1)); + gcc_assert (size_zero_node == TYPE_MIN_VALUE (d2)); + + tree d = fold_build3_loc (UNKNOWN_LOCATION, COND_EXPR, sizetype, + cond, TYPE_MAX_VALUE (d1), + TYPE_MAX_VALUE (d2)); + + td = build_index_type (d); + } /* Merge the element types, and have a size if either arg has one. We may have qualifiers on the element types. To set up TYPE_MAIN_VARIANT correctly, we need to form the composite of the unqualified types and add the qualifiers back at the end. */ - quals = TYPE_QUALS (strip_array_types (elt)); - unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED); - t1 = c_build_array_type (unqual_elt, TYPE_DOMAIN (use1 ? t1 : t2)); + int quals = TYPE_QUALS (strip_array_types (elt)); + tree unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED); + + t1 = c_build_array_type (unqual_elt, td); /* Check that a type which has a varying outermost dimension got marked has having a variable size. */ @@ -773,7 +810,7 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) construction, return it. */ for (struct composite_cache *c = cache; c != NULL; c = c->next) - if (c->t1 == t1 && c->t2 == t2) + if ((c->t1 == t1 && c->t2 == t2) || (c->t1 == t2 && c->t2 == t1)) return c->composite; /* Otherwise, create a new type node and link it into the cache. */ @@ -804,7 +841,7 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) gcc_assert (DECL_NAME (a) == DECL_NAME (b)); gcc_checking_assert (!DECL_NAME (a) || comptypes (ta, tb)); - tree t = composite_type_internal (ta, tb, cache); + tree t = composite_type_internal (ta, tb, cond, cache); tree f = build_decl (input_location, FIELD_DECL, DECL_NAME (a), t); DECL_PACKED (f) = DECL_PACKED (a); @@ -843,12 +880,7 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) n = finish_struct (input_location, n, fields, attributes, NULL, &expr); - n = qualify_type (n, t1); - - gcc_checking_assert (!TYPE_NAME (n) || comptypes (n, t1)); - gcc_checking_assert (!TYPE_NAME (n) || comptypes (n, t2)); - - return n; + return qualify_type (n, t1); } /* FALLTHRU */ case ENUMERAL_TYPE: @@ -866,8 +898,8 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) /* Function types: prefer the one that specified arg types. If both do, merge the arg types. Also merge the return types. */ { - tree valtype = composite_type_internal (TREE_TYPE (t1), - TREE_TYPE (t2), cache); + tree valtype = composite_type_internal (TREE_TYPE (t1), TREE_TYPE (t2), + cond, cache); tree p1 = TYPE_ARG_TYPES (t1); tree p2 = TYPE_ARG_TYPES (t2); int len; @@ -912,15 +944,8 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) for (; p1 && p1 != void_list_node; p1 = TREE_CHAIN (p1), p2 = TREE_CHAIN (p2), n = TREE_CHAIN (n)) { - tree mv1 = TREE_VALUE (p1); - if (mv1 && mv1 != error_mark_node - && TREE_CODE (mv1) != ARRAY_TYPE) - mv1 = TYPE_MAIN_VARIANT (mv1); - - tree mv2 = TREE_VALUE (p2); - if (mv2 && mv2 != error_mark_node - && TREE_CODE (mv2) != ARRAY_TYPE) - mv2 = TYPE_MAIN_VARIANT (mv2); + tree mv1 = remove_qualifiers (TREE_VALUE (p1)); + tree mv2 = remove_qualifiers (TREE_VALUE (p2)); /* A null type means arg type is not specified. Take whatever the other function type has. */ @@ -953,7 +978,7 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) { TREE_VALUE (n) = composite_type_internal (TREE_TYPE (memb), TREE_VALUE (p2), - cache); + cond, cache); pedwarn (input_location, OPT_Wpedantic, "function types not truly compatible in ISO C"); goto parm_done; @@ -976,14 +1001,14 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) TREE_VALUE (n) = composite_type_internal (TREE_TYPE (memb), TREE_VALUE (p1), - cache); + cond, cache); pedwarn (input_location, OPT_Wpedantic, "function types not truly compatible in ISO C"); goto parm_done; } } } - TREE_VALUE (n) = composite_type_internal (mv1, mv2, cache); + TREE_VALUE (n) = composite_type_internal (mv1, mv2, cond, cache); parm_done: ; } @@ -998,10 +1023,23 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) } tree -composite_type (tree t1, tree t2) +composite_type_cond (tree t1, tree t2, tree cond) { + gcc_checking_assert (comptypes_check_for_composite (t1, t2)); + struct composite_cache cache = { }; - return composite_type_internal (t1, t2, &cache); + tree n = composite_type_internal (t1, t2, cond, &cache); + + gcc_checking_assert (comptypes_check_for_composite (n, t1)); + gcc_checking_assert (comptypes_check_for_composite (n, t2)); + return n; +} + + +tree +composite_type (tree t1, tree t2) +{ + return composite_type_cond (t1, t2, NULL_TREE); } /* Return the type of a conditional expression between pointers to @@ -1011,12 +1049,9 @@ composite_type (tree t1, tree t2) true; if that isn't so, this may crash. */ static tree -common_pointer_type (tree t1, tree t2) +common_pointer_type (tree t1, tree t2, tree cond) { tree attributes; - tree pointed_to_1, mv1; - tree pointed_to_2, mv2; - tree target; unsigned target_quals; addr_space_t as1, as2, as_common; int quals1, quals2; @@ -1038,15 +1073,11 @@ common_pointer_type (tree t1, tree t2) attributes = targetm.merge_type_attributes (t1, t2); /* Find the composite type of the target types, and combine the - qualifiers of the two types' targets. Do not lose qualifiers on - array element types by taking the TYPE_MAIN_VARIANT. */ - mv1 = pointed_to_1 = TREE_TYPE (t1); - mv2 = pointed_to_2 = TREE_TYPE (t2); - if (TREE_CODE (mv1) != ARRAY_TYPE) - mv1 = TYPE_MAIN_VARIANT (pointed_to_1); - if (TREE_CODE (mv2) != ARRAY_TYPE) - mv2 = TYPE_MAIN_VARIANT (pointed_to_2); - target = composite_type (mv1, mv2); + qualifiers of the two types' targets. */ + tree pointed_to_1 = TREE_TYPE (t1); + tree pointed_to_2 = TREE_TYPE (t2); + tree target = composite_type_cond (TYPE_MAIN_VARIANT (pointed_to_1), + TYPE_MAIN_VARIANT (pointed_to_2), cond); /* Strip array types to get correct qualifier for pointers to arrays */ quals1 = TYPE_QUALS_NO_ADDR_SPACE (strip_array_types (pointed_to_1)); @@ -1451,16 +1482,39 @@ comptypes_verify (tree type1, tree type2) } struct comptypes_data { + + /* output */ bool enum_and_int_p; bool different_types_p; bool warning_needed; + + /* context */ bool anon_field; bool pointedto; + + /* configuration */ bool equiv; + bool ignore_promoting_args; const struct tagged_tu_seen_cache* cache; }; + +/* Helper function for composite_type. This function ignores when the + function type of an old-style declaration is incompatible with a type + of a declaration with prototype because some are arguments are not + self-promoting. This is ignored only for function types but not + ignored in a nested context. */ + +static bool +comptypes_check_for_composite (tree t1, tree t2) +{ + struct comptypes_data data = { }; + data.ignore_promoting_args = FUNCTION_TYPE == TREE_CODE (t1); + return comptypes_internal (t1, t2, &data); +} + + /* C implementation of compatible_types_for_indirection_note_p. */ bool @@ -1590,6 +1644,10 @@ comptypes_equiv_p (tree type1, tree type2) permitted in C11 typedef redeclarations, then this sets 'different_types_p' in DATA to true; it is never set to false, but may or may not be set if the types are incompatible. + If two functions types are not compatible only because one is + an old-style definition that does not have self-promoting arguments, + then this can be ignored by setting 'ignore_promoting_args_p'. + For 'equiv' we can compute equivalency classes (see above). This differs from comptypes, in that we don't free the seen types. */ @@ -1788,15 +1846,9 @@ comp_target_types (location_t location, tree ttl, tree ttr) val_ped = comptypes (mvl, mvr); /* Qualifiers on element types of array types that are - pointer targets are lost by taking their TYPE_MAIN_VARIANT. */ - - mvl = (TYPE_ATOMIC (strip_array_types (mvl)) - ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvl), TYPE_QUAL_ATOMIC) - : TYPE_MAIN_VARIANT (mvl)); - - mvr = (TYPE_ATOMIC (strip_array_types (mvr)) - ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr), TYPE_QUAL_ATOMIC) - : TYPE_MAIN_VARIANT (mvr)); + pointer targets are also removed. */ + mvl = remove_qualifiers (mvl); + mvr = remove_qualifiers (mvr); enum_and_int_p = false; val = comptypes_check_enum_int (mvl, mvr, &enum_and_int_p); @@ -1947,6 +1999,9 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, ft2 = DECL_BIT_FIELD_TYPE (s2); } + if (!ft1 || !ft2) + return false; + if (TREE_CODE (ft1) == ERROR_MARK || TREE_CODE (ft2) == ERROR_MARK) return false; @@ -2019,14 +2074,8 @@ static bool function_types_compatible_p (const_tree f1, const_tree f2, struct comptypes_data *data) { - tree args1, args2; - /* 1 if no need for warning yet, 2 if warning cause has been seen. */ - int val = 1; - int val1; - tree ret1, ret2; - - ret1 = TREE_TYPE (f1); - ret2 = TREE_TYPE (f2); + tree ret1 = TREE_TYPE (f1); + tree ret2 = TREE_TYPE (f2); /* 'volatile' qualifiers on a function's return type used to mean the function is noreturn. */ @@ -2038,12 +2087,17 @@ function_types_compatible_p (const_tree f1, const_tree f2, if (TYPE_VOLATILE (ret2)) ret2 = build_qualified_type (TYPE_MAIN_VARIANT (ret2), TYPE_QUALS (ret2) & ~TYPE_QUAL_VOLATILE); - val = comptypes_internal (ret1, ret2, data); - if (val == 0) - return 0; - args1 = TYPE_ARG_TYPES (f1); - args2 = TYPE_ARG_TYPES (f2); + bool ignore_pargs = data->ignore_promoting_args; + data->ignore_promoting_args = false; + + if (!comptypes_internal (ret1, ret2, data)) + return false; + + data->ignore_promoting_args = ignore_pargs; + + tree args1 = TYPE_ARG_TYPES (f1); + tree args2 = TYPE_ARG_TYPES (f2); if ((args1 == NULL_TREE) != (args2 == NULL_TREE)) data->different_types_p = true; @@ -2054,40 +2108,33 @@ function_types_compatible_p (const_tree f1, const_tree f2, if (args1 == NULL_TREE) { if (TYPE_NO_NAMED_ARGS_STDARG_P (f1) != TYPE_NO_NAMED_ARGS_STDARG_P (f2)) - return 0; - if (!self_promoting_args_p (args2)) - return 0; + return false; + if (!(data->ignore_promoting_args || self_promoting_args_p (args2))) + return false; + data->ignore_promoting_args = false; /* If one of these types comes from a non-prototype fn definition, compare that with the other type's arglist. If they don't match, ask for a warning (but no error). */ if (TYPE_ACTUAL_ARG_TYPES (f1) - && type_lists_compatible_p (args2, TYPE_ACTUAL_ARG_TYPES (f1), - data) != 1) - { - val = 1; - data->warning_needed = true; - } - return val; + && !type_lists_compatible_p (args2, TYPE_ACTUAL_ARG_TYPES (f1), data)) + data->warning_needed = true; + return true; } if (args2 == NULL_TREE) { if (TYPE_NO_NAMED_ARGS_STDARG_P (f1) != TYPE_NO_NAMED_ARGS_STDARG_P (f2)) - return 0; - if (!self_promoting_args_p (args1)) - return 0; + return false; + if (!(data->ignore_promoting_args || self_promoting_args_p (args1))) + return false; + data->ignore_promoting_args = false; if (TYPE_ACTUAL_ARG_TYPES (f2) - && type_lists_compatible_p (args1, TYPE_ACTUAL_ARG_TYPES (f2), - data) != 1) - { - val = 1; - data->warning_needed = true; - } - return val; + && !type_lists_compatible_p (args1, TYPE_ACTUAL_ARG_TYPES (f2), data)) + data->warning_needed = true; + return true; } /* Both types have argument lists: compare them and propagate results. */ - val1 = type_lists_compatible_p (args1, args2, data); - return val1; + return type_lists_compatible_p (args1, args2, data); } /* Check two lists of types for compatibility, returning false for @@ -2099,25 +2146,16 @@ type_lists_compatible_p (const_tree args1, const_tree args2, { while (1) { - tree a1, mv1, a2, mv2; if (args1 == NULL_TREE && args2 == NULL_TREE) return true; /* If one list is shorter than the other, they fail to match. */ if (args1 == NULL_TREE || args2 == NULL_TREE) - return 0; - mv1 = a1 = TREE_VALUE (args1); - mv2 = a2 = TREE_VALUE (args2); - if (mv1 && mv1 != error_mark_node && TREE_CODE (mv1) != ARRAY_TYPE) - mv1 = (TYPE_ATOMIC (mv1) - ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv1), - TYPE_QUAL_ATOMIC) - : TYPE_MAIN_VARIANT (mv1)); - if (mv2 && mv2 != error_mark_node && TREE_CODE (mv2) != ARRAY_TYPE) - mv2 = (TYPE_ATOMIC (mv2) - ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv2), - TYPE_QUAL_ATOMIC) - : TYPE_MAIN_VARIANT (mv2)); + return false; + tree a1 = TREE_VALUE (args1); + tree a2 = TREE_VALUE (args2); + tree mv1 = remove_qualifiers (a1); + tree mv2 = remove_qualifiers (a2); /* A null pointer instead of a type means there is supposed to be an argument but nothing is specified about what type it has. @@ -2127,12 +2165,12 @@ type_lists_compatible_p (const_tree args1, const_tree args2, if (a1 == NULL_TREE) { if (c_type_promotes_to (a2) != a2) - return 0; + return false; } else if (a2 == NULL_TREE) { if (c_type_promotes_to (a1) != a1) - return 0; + return false; } /* If one of the lists has an error marker, ignore this arg. */ else if (TREE_CODE (a1) == ERROR_MARK @@ -2154,18 +2192,12 @@ type_lists_compatible_p (const_tree args1, const_tree args2, for (memb = TYPE_FIELDS (a1); memb; memb = DECL_CHAIN (memb)) { - tree mv3 = TREE_TYPE (memb); - if (mv3 && mv3 != error_mark_node - && TREE_CODE (mv3) != ARRAY_TYPE) - mv3 = (TYPE_ATOMIC (mv3) - ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv3), - TYPE_QUAL_ATOMIC) - : TYPE_MAIN_VARIANT (mv3)); + tree mv3 = remove_qualifiers (TREE_TYPE (memb)); if (comptypes_internal (mv3, mv2, data)) break; } if (memb == NULL_TREE) - return 0; + return false; } else if (TREE_CODE (a2) == UNION_TYPE && (TYPE_NAME (a2) == NULL_TREE @@ -2178,21 +2210,15 @@ type_lists_compatible_p (const_tree args1, const_tree args2, for (memb = TYPE_FIELDS (a2); memb; memb = DECL_CHAIN (memb)) { - tree mv3 = TREE_TYPE (memb); - if (mv3 && mv3 != error_mark_node - && TREE_CODE (mv3) != ARRAY_TYPE) - mv3 = (TYPE_ATOMIC (mv3) - ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv3), - TYPE_QUAL_ATOMIC) - : TYPE_MAIN_VARIANT (mv3)); + tree mv3 = remove_qualifiers (TREE_TYPE (memb)); if (comptypes_internal (mv3, mv1, data)) break; } if (memb == NULL_TREE) - return 0; + return false; } else - return 0; + return false; } args1 = TREE_CHAIN (args1); @@ -2316,14 +2342,30 @@ mark_exp_read (tree exp) case PARM_DECL: DECL_READ_P (exp) = 1; break; + CASE_CONVERT: + if (VOID_TYPE_P (TREE_TYPE (exp))) + switch (TREE_CODE (TREE_OPERAND (exp, 0))) + { + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + return; + default: + break; + } + /* FALLTHRU */ case ARRAY_REF: case COMPONENT_REF: case MODIFY_EXPR: case REALPART_EXPR: case IMAGPART_EXPR: - CASE_CONVERT: case ADDR_EXPR: case VIEW_CONVERT_EXPR: + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + case POSTDECREMENT_EXPR: mark_exp_read (TREE_OPERAND (exp, 0)); break; case COMPOUND_EXPR: @@ -2638,6 +2680,20 @@ convert_lvalue_to_rvalue (location_t loc, struct c_expr exp, return exp; } +/* Wrapper for the overload above, same arguments but for tree rather than + c_expr. This is important for hardbools to decay to bools. */ + +static inline tree +convert_lvalue_to_rvalue (location_t loc, tree val, + bool convert_p, bool read_p, bool for_init = false) +{ + struct c_expr expr; + memset (&expr, 0, sizeof (expr)); + expr.value = val; + expr = convert_lvalue_to_rvalue (loc, expr, convert_p, read_p, for_init); + return expr.value; +} + /* EXP is an expression of integer type. Apply the integer promotions to it and return the promoted value. */ @@ -2988,8 +3044,8 @@ build_counted_by_ref (tree datum, tree subdatum, tree *counted_by_type) to: - (*.ACCESS_WITH_SIZE (REF, COUNTED_BY_REF, 1, (TYPE_OF_SIZE)0, -1, - (TYPE_OF_ARRAY *)0)) + (*.ACCESS_WITH_SIZE (REF, COUNTED_BY_REF, (* TYPE_OF_SIZE)0, + TYPE_SIZE_UNIT for element) NOTE: The return type of this function is the POINTER type pointing to the original flexible array type. @@ -2998,11 +3054,11 @@ build_counted_by_ref (tree datum, tree subdatum, tree *counted_by_type) The type of the first argument of this function is a POINTER type to the original flexible array type. - The 4th argument of the call is a constant 0 with the TYPE of the - object pointed by COUNTED_BY_REF. + The 3rd argument of the call is a constant 0 with the pointer TYPE whose + pointee type is the TYPE of the object pointed by COUNTED_BY_REF. - The 6th argument of the call is a constant 0 with the pointer TYPE - to the original flexible array type. + The 4th argument of the call is the TYPE_SIZE_UNIT of the element TYPE + of the array. */ static tree @@ -3013,20 +3069,22 @@ build_access_with_size_for_counted_by (location_t loc, tree ref, gcc_assert (c_flexible_array_member_type_p (TREE_TYPE (ref))); /* The result type of the call is a pointer to the flexible array type. */ tree result_type = c_build_pointer_type (TREE_TYPE (ref)); + tree element_size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ref))); + tree first_param = c_fully_fold (array_to_pointer_conversion (loc, ref), false, NULL); tree second_param = c_fully_fold (counted_by_ref, false, NULL); + tree third_param = build_int_cst (build_pointer_type (counted_by_type), 0); tree call = build_call_expr_internal_loc (loc, IFN_ACCESS_WITH_SIZE, - result_type, 6, + result_type, 4, first_param, second_param, - build_int_cst (integer_type_node, 1), - build_int_cst (counted_by_type, 0), - build_int_cst (integer_type_node, -1), - build_int_cst (result_type, 0)); + third_param, + element_size); + /* Wrap the call with an INDIRECT_REF with the flexible array type. */ call = build1 (INDIRECT_REF, TREE_TYPE (ref), call); SET_EXPR_LOCATION (call, loc); @@ -3540,7 +3598,7 @@ build_external_ref (location_t loc, tree id, bool fun, tree *type) if (TREE_CODE (ref) == FUNCTION_DECL && !in_alignof) { - if (!in_sizeof && !in_typeof) + if (!in_sizeof && !in_typeof && !in_countof) C_DECL_USED (ref) = 1; else if (DECL_INITIAL (ref) == NULL_TREE && DECL_EXTERNAL (ref) @@ -3596,7 +3654,7 @@ struct maybe_used_decl { /* The decl. */ tree decl; - /* The level seen at (in_sizeof + in_typeof). */ + /* The level seen at (in_sizeof + in_typeof + in_countof). */ int level; /* The next one at this level or above, or NULL. */ struct maybe_used_decl *next; @@ -3614,7 +3672,7 @@ record_maybe_used_decl (tree decl) { struct maybe_used_decl *t = XOBNEW (&parser_obstack, struct maybe_used_decl); t->decl = decl; - t->level = in_sizeof + in_typeof; + t->level = in_sizeof + in_typeof + in_countof; t->next = maybe_used_decls; maybe_used_decls = t; } @@ -3628,7 +3686,7 @@ void pop_maybe_used (bool used) { struct maybe_used_decl *p = maybe_used_decls; - int cur_level = in_sizeof + in_typeof; + int cur_level = in_sizeof + in_typeof + in_countof; while (p && p->level > cur_level) { if (used) @@ -3738,6 +3796,110 @@ c_expr_sizeof_type (location_t loc, struct c_type_name *t) return ret; } +static bool +is_top_array_vla (tree type) +{ + bool zero, var; + tree d; + + if (TREE_CODE (type) != ARRAY_TYPE) + return false; + if (!COMPLETE_TYPE_P (type)) + return false; + + d = TYPE_DOMAIN (type); + zero = !TYPE_MAX_VALUE (d); + if (zero) + return false; + + var = (TREE_CODE (TYPE_MIN_VALUE (d)) != INTEGER_CST + || TREE_CODE (TYPE_MAX_VALUE (d)) != INTEGER_CST); + return var; +} + +/* Return the result of countof applied to EXPR. */ + +struct c_expr +c_expr_countof_expr (location_t loc, struct c_expr expr) +{ + struct c_expr ret; + if (expr.value == error_mark_node) + { + ret.value = error_mark_node; + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + ret.m_decimal = 0; + pop_maybe_used (false); + } + else + { + bool expr_const_operands = true; + + tree folded_expr = c_fully_fold (expr.value, require_constant_value, + &expr_const_operands); + ret.value = c_countof_type (loc, TREE_TYPE (folded_expr)); + c_last_sizeof_arg = expr.value; + c_last_sizeof_loc = loc; + ret.original_code = COUNTOF_EXPR; + ret.original_type = NULL; + ret.m_decimal = 0; + if (is_top_array_vla (TREE_TYPE (folded_expr))) + { + /* countof is evaluated when given a vla. */ + ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value), + folded_expr, ret.value); + C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !expr_const_operands; + SET_EXPR_LOCATION (ret.value, loc); + } + pop_maybe_used (is_top_array_vla (TREE_TYPE (folded_expr))); + } + return ret; +} + +/* Return the result of countof applied to T, a structure for the type + name passed to countof (rather than the type itself). LOC is the + location of the original expression. */ + +struct c_expr +c_expr_countof_type (location_t loc, struct c_type_name *t) +{ + tree type; + struct c_expr ret; + tree type_expr = NULL_TREE; + bool type_expr_const = true; + type = groktypename (t, &type_expr, &type_expr_const); + ret.value = c_countof_type (loc, type); + c_last_sizeof_arg = type; + c_last_sizeof_loc = loc; + ret.original_code = COUNTOF_EXPR; + ret.original_type = NULL; + ret.m_decimal = 0; + 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) + && is_top_array_vla (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 + the result of countof does not get folded to a constant by + c_fully_fold, because if the number of elements is evaluated + the result is not constant and so + constraints on zero or negative size arrays must not be applied + when this countof call is inside another array declarator. */ + if (!type_expr) + type_expr = integer_zero_node; + ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value), + type_expr, ret.value); + C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !type_expr_const; + } + pop_maybe_used (type != error_mark_node ? is_top_array_vla (type) : false); + return ret; +} + /* Build a function call to function FUNCTION with parameters PARAMS. The function call is at LOC. PARAMS is a list--a chain of TREE_LIST nodes--in which the @@ -4336,7 +4498,8 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree fntype, builtin_typetail = NULL_TREE; } - if (!typetail && parmnum == 0 && !TYPE_NO_NAMED_ARGS_STDARG_P (fntype)) + if (!typetail && parmnum == 0 && !TYPE_NO_NAMED_ARGS_STDARG_P (fntype) + && !(fundecl && fndecl_built_in_p (fundecl))) { auto_diagnostic_group d; bool warned; @@ -4809,7 +4972,7 @@ pointer_diff (location_t loc, tree op0, tree op1, tree *instrument_expr) if (!addr_space_superset (as0, as1, &as_common)) gcc_unreachable (); - common_type = common_pointer_type (TREE_TYPE (op0), TREE_TYPE (op1)); + common_type = common_pointer_type (TREE_TYPE (op0), TREE_TYPE (op1), NULL_TREE); op0 = convert (common_type, op0); op1 = convert (common_type, op1); } @@ -5154,7 +5317,9 @@ cas_loop: /* newval = old + val; */ if (rhs_type != rhs_semantic_type) val = build1 (EXCESS_PRECISION_EXPR, nonatomic_rhs_semantic_type, val); - rhs = build_binary_op (loc, modifycode, old, val, true); + rhs = build_binary_op (loc, modifycode, + convert_lvalue_to_rvalue (loc, old, true, true), + val, true); if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR) { tree eptype = TREE_TYPE (rhs); @@ -5610,7 +5775,48 @@ build_unary_op (location_t location, enum tree_code code, tree xarg, goto return_build_unary_op; } - if (C_BOOLEAN_TYPE_P (TREE_TYPE (arg))) + tree true_res; + if (c_hardbool_type_attr (TREE_TYPE (arg), NULL, &true_res)) + { + tree larg = stabilize_reference (arg); + tree sarg = save_expr (larg); + switch (code) + { + case PREINCREMENT_EXPR: + val = build2 (MODIFY_EXPR, TREE_TYPE (larg), larg, true_res); + val = build2 (COMPOUND_EXPR, TREE_TYPE (larg), sarg, val); + break; + case POSTINCREMENT_EXPR: + val = build2 (MODIFY_EXPR, TREE_TYPE (larg), larg, true_res); + val = build2 (COMPOUND_EXPR, TREE_TYPE (larg), val, sarg); + val = build2 (COMPOUND_EXPR, TREE_TYPE (larg), sarg, val); + break; + case PREDECREMENT_EXPR: + { + tree rarg = convert_lvalue_to_rvalue (location, sarg, + true, true); + rarg = invert_truthvalue_loc (location, rarg); + rarg = convert (TREE_TYPE (sarg), rarg); + val = build2 (MODIFY_EXPR, TREE_TYPE (larg), larg, rarg); + } + break; + case POSTDECREMENT_EXPR: + { + tree rarg = convert_lvalue_to_rvalue (location, sarg, + true, true); + rarg = invert_truthvalue_loc (location, rarg); + tree iarg = convert (TREE_TYPE (larg), rarg); + val = build2 (MODIFY_EXPR, TREE_TYPE (larg), larg, iarg); + val = build2 (COMPOUND_EXPR, TREE_TYPE (larg), val, sarg); + val = build2 (COMPOUND_EXPR, TREE_TYPE (larg), sarg, val); + } + break; + default: + gcc_unreachable (); + } + TREE_SIDE_EFFECTS (val) = 1; + } + else if (C_BOOLEAN_TYPE_P (TREE_TYPE (arg))) val = boolean_increment (code, arg); else val = build2 (code, TREE_TYPE (arg), arg, inc); @@ -6263,7 +6469,10 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, addr_space_t as_common; if (comp_target_types (colon_loc, type1, type2)) - result_type = common_pointer_type (type1, type2); + { + ifexp = save_expr (ifexp); + result_type = common_pointer_type (type1, type2, ifexp); + } else if (null_pointer_constant_p (orig_op1)) result_type = type2; else if (null_pointer_constant_p (orig_op2)) @@ -6316,14 +6525,16 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, else { int qual = ENCODE_QUAL_ADDR_SPACE (as_common); - diagnostic_t kind = DK_PERMERROR; + enum diagnostics::kind kind = diagnostics::kind::permerror; if (!flag_isoc99) /* This downgrade to a warning ensures that -std=gnu89 -pedantic-errors does not flag these mismatches between - builtins as errors (as DK_PERMERROR would). ISO C99 - and later do not have implicit function declarations, + builtins as errors (as diagnostics::kind::permerror would) + ISO C99 and later do not have implicit function declarations, so the mismatch cannot occur naturally there. */ - kind = bltin1 && bltin2 ? DK_WARNING : DK_PEDWARN; + kind = (bltin1 && bltin2 + ? diagnostics::kind::warning + : diagnostics::kind::pedwarn); if (emit_diagnostic (kind, colon_loc, OPT_Wincompatible_pointer_types, "pointer type mismatch " "in conditional expression")) @@ -7207,8 +7418,23 @@ build_modify_expr (location_t location, tree lhs, tree lhs_origtype, newrhs = build1 (EXCESS_PRECISION_EXPR, TREE_TYPE (rhs), newrhs); } - newrhs = build_binary_op (location, - modifycode, lhs, newrhs, true); + bool clear_decl_read = false; + if ((VAR_P (lhs) || TREE_CODE (lhs) == PARM_DECL) + && !DECL_READ_P (lhs) + && (VAR_P (lhs) ? warn_unused_but_set_variable + : warn_unused_but_set_parameter) > 2) + { + mark_exp_read (newrhs); + if (!DECL_READ_P (lhs)) + clear_decl_read = true; + } + + newrhs = build_binary_op (location, modifycode, + convert_lvalue_to_rvalue (location, lhs, + true, true), + newrhs, true); + if (clear_decl_read) + DECL_READ_P (lhs) = 0; /* The original type of the right hand side is no longer meaningful. */ @@ -7371,10 +7597,7 @@ find_anonymous_field_with_type (tree struct_type, tree type) field != NULL_TREE; field = TREE_CHAIN (field)) { - tree fieldtype = (TYPE_ATOMIC (TREE_TYPE (field)) - ? c_build_qualified_type (TREE_TYPE (field), - TYPE_QUAL_ATOMIC) - : TYPE_MAIN_VARIANT (TREE_TYPE (field))); + tree fieldtype = remove_qualifiers (TREE_TYPE (field)); if (DECL_NAME (field) == NULL && comptypes (type, fieldtype)) { @@ -7412,10 +7635,7 @@ convert_to_anonymous_field (location_t location, tree type, tree rhs) gcc_assert (RECORD_OR_UNION_TYPE_P (rhs_struct_type)); gcc_assert (POINTER_TYPE_P (type)); - lhs_main_type = (TYPE_ATOMIC (TREE_TYPE (type)) - ? c_build_qualified_type (TREE_TYPE (type), - TYPE_QUAL_ATOMIC) - : TYPE_MAIN_VARIANT (TREE_TYPE (type))); + lhs_main_type = remove_qualifiers (TREE_TYPE (type)); found_field = NULL_TREE; found_sub_field = false; @@ -7426,10 +7646,7 @@ convert_to_anonymous_field (location_t location, tree type, tree rhs) if (DECL_NAME (field) != NULL_TREE || !RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))) continue; - tree fieldtype = (TYPE_ATOMIC (TREE_TYPE (field)) - ? c_build_qualified_type (TREE_TYPE (field), - TYPE_QUAL_ATOMIC) - : TYPE_MAIN_VARIANT (TREE_TYPE (field))); + tree fieldtype = remove_qualifiers (TREE_TYPE (field)); if (comptypes (lhs_main_type, fieldtype)) { if (found_field != NULL_TREE) @@ -7477,7 +7694,8 @@ error_init (location_t loc, const char *gmsgid, ...) /* The gmsgid may be a format string with %< and %>. */ va_list ap; va_start (ap, gmsgid); - bool warned = emit_diagnostic_valist (DK_ERROR, loc, -1, gmsgid, &ap); + bool warned = emit_diagnostic_valist (diagnostics::kind::error, + loc, -1, gmsgid, &ap); va_end (ap); ofwhat = print_spelling ((char *) alloca (spelling_length () + 1)); @@ -7489,7 +7707,7 @@ error_init (location_t loc, const char *gmsgid, ...) static bool ATTRIBUTE_GCC_DIAG (3,0) pedwarn_permerror_init (location_t loc, int opt, const char *gmsgid, - va_list *ap, diagnostic_t kind) + va_list *ap, enum diagnostics::kind kind) { /* Use the location where a macro was expanded rather than where it was defined to make sure macros defined in system headers @@ -7516,7 +7734,8 @@ pedwarn_init (location_t loc, int opt, const char *gmsgid, ...) { va_list ap; va_start (ap, gmsgid); - bool warned = pedwarn_permerror_init (loc, opt, gmsgid, &ap, DK_PEDWARN); + bool warned = pedwarn_permerror_init (loc, opt, gmsgid, &ap, + diagnostics::kind::pedwarn); va_end (ap); return warned; } @@ -7528,7 +7747,8 @@ permerror_init (location_t loc, int opt, const char *gmsgid, ...) { va_list ap; va_start (ap, gmsgid); - bool warned = pedwarn_permerror_init (loc, opt, gmsgid, &ap, DK_PERMERROR); + bool warned = pedwarn_permerror_init (loc, opt, gmsgid, &ap, + diagnostics::kind::permerror); va_end (ap); return warned; } @@ -8186,23 +8406,14 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, tree ttl = TREE_TYPE (type); tree ttr = TREE_TYPE (rhstype); - tree mvl = ttl; - tree mvr = ttr; bool is_opaque_pointer; bool target_cmp = false; /* Cache comp_target_types () result. */ addr_space_t asl; addr_space_t asr; - if (TREE_CODE (mvl) != ARRAY_TYPE) - mvl = (TYPE_ATOMIC (mvl) - ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvl), - TYPE_QUAL_ATOMIC) - : TYPE_MAIN_VARIANT (mvl)); - if (TREE_CODE (mvr) != ARRAY_TYPE) - mvr = (TYPE_ATOMIC (mvr) - ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr), - TYPE_QUAL_ATOMIC) - : TYPE_MAIN_VARIANT (mvr)); + tree mvl = remove_qualifiers (ttl); + tree mvr = remove_qualifiers (ttr); + /* Opaque pointers are treated like void pointers. */ is_opaque_pointer = vector_targets_convertible_p (ttl, ttr); @@ -9142,8 +9353,24 @@ check_constexpr_init (location_t loc, tree type, tree init, /* The initializer must be an integer constant expression, representable in the target type. */ if (!int_const_expr) - error_at (loc, "%<constexpr%> integer initializer is not an " - "integer constant expression"); + { + if (TREE_CODE (init) == RAW_DATA_CST + && TYPE_PRECISION (type) == CHAR_BIT) + { + if (!TYPE_UNSIGNED (type)) + for (unsigned int i = 0; + i < (unsigned) RAW_DATA_LENGTH (init); ++i) + if (RAW_DATA_SCHAR_ELT (init, i) < 0) + { + error_at (loc, "%<constexpr%> initializer not " + "representable in type of object"); + break; + } + } + else + error_at (loc, "%<constexpr%> integer initializer is not an " + "integer constant expression"); + } else if (!int_fits_type_p (init, type)) error_at (loc, "%<constexpr%> initializer not representable in " "type of object"); @@ -12518,7 +12745,8 @@ build_asm_expr (location_t loc, tree string, tree outputs, tree inputs, oconstraints[i] = constraint; if (parse_output_constraint (&constraint, i, ninputs, noutputs, - &allows_mem, &allows_reg, &is_inout)) + &allows_mem, &allows_reg, &is_inout, + nullptr)) { /* If the operand is going to end up in memory, mark it addressable. */ @@ -12579,7 +12807,8 @@ build_asm_expr (location_t loc, tree string, tree outputs, tree inputs, input = TREE_VALUE (tail); if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0, - oconstraints, &allows_mem, &allows_reg)) + oconstraints, &allows_mem, &allows_reg, + nullptr)) { /* If the operand is going to end up in memory, mark it addressable. */ @@ -12595,11 +12824,9 @@ build_asm_expr (location_t loc, tree string, tree outputs, tree inputs, } else { - struct c_expr expr; - memset (&expr, 0, sizeof (expr)); - expr.value = input; - expr = convert_lvalue_to_rvalue (loc, expr, true, false); - input = c_fully_fold (expr.value, false, NULL); + input = c_fully_fold (convert_lvalue_to_rvalue (loc, input, + true, false), + false, NULL); if (input != error_mark_node && VOID_TYPE_P (TREE_TYPE (input))) { @@ -12761,7 +12988,9 @@ c_finish_return (location_t loc, tree retval, tree origtype, bool musttail_p) && valtype != NULL_TREE && TREE_CODE (valtype) != VOID_TYPE) { no_warning = true; - if (emit_diagnostic (flag_isoc99 ? DK_PERMERROR : DK_WARNING, + if (emit_diagnostic (flag_isoc99 + ? diagnostics::kind::permerror + : diagnostics::kind::warning, loc, OPT_Wreturn_mismatch, "%<return%> with no value," " in function returning non-void")) @@ -14253,7 +14482,7 @@ build_binary_op (location_t location, enum tree_code code, Otherwise, the targets must be compatible and both must be object or both incomplete. */ if (comp_target_types (location, type0, type1)) - result_type = common_pointer_type (type0, type1); + result_type = common_pointer_type (type0, type1, NULL_TREE); else if (!addr_space_superset (as0, as1, &as_common)) { error_at (location, "comparison of pointers to " @@ -14392,7 +14621,7 @@ build_binary_op (location_t location, enum tree_code code, if (comp_target_types (location, type0, type1)) { - result_type = common_pointer_type (type0, type1); + result_type = common_pointer_type (type0, type1, NULL_TREE); if (!COMPLETE_TYPE_P (TREE_TYPE (type0)) != !COMPLETE_TYPE_P (TREE_TYPE (type1))) pedwarn_c99 (location, OPT_Wpedantic, @@ -15219,12 +15448,8 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, /* If the array section is pointer based and the pointer itself is _Atomic qualified, we need to atomically load the pointer. */ - c_expr expr; - memset (&expr, 0, sizeof (expr)); - expr.value = ret; - expr = convert_lvalue_to_rvalue (OMP_CLAUSE_LOCATION (c), - expr, false, false); - ret = expr.value; + ret = convert_lvalue_to_rvalue (OMP_CLAUSE_LOCATION (c), + ret, false, false); } return ret; } @@ -15509,9 +15734,7 @@ handle_omp_array_sections (tree &c, enum c_omp_region_type ort) tree *tp = &OMP_CLAUSE_DECL (c); 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) + && OMP_ITERATOR_DECL_P (*tp)) tp = &TREE_VALUE (*tp); tree first = handle_omp_array_sections_1 (c, *tp, types, maybe_zero_len, first_non_one, @@ -16069,7 +16292,14 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) /* We've reached the end of a list of expanded nodes. Reset the group start pointer. */ if (c == grp_sentinel) - grp_start_p = NULL; + { + if (grp_start_p + && OMP_CLAUSE_HAS_ITERATORS (*grp_start_p)) + for (tree gc = *grp_start_p; gc != grp_sentinel; + gc = OMP_CLAUSE_CHAIN (gc)) + OMP_CLAUSE_ITERATORS (gc) = OMP_CLAUSE_ITERATORS (*grp_start_p); + grp_start_p = NULL; + } switch (OMP_CLAUSE_CODE (c)) { @@ -16708,9 +16938,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) /* 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) + if (OMP_ITERATOR_DECL_P (t)) { if (TREE_PURPOSE (t) != last_iterators) last_iterators_remove @@ -16810,10 +17038,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) break; } } - if (TREE_CODE (OMP_CLAUSE_DECL (c)) == TREE_LIST - && TREE_PURPOSE (OMP_CLAUSE_DECL (c)) - && (TREE_CODE (TREE_PURPOSE (OMP_CLAUSE_DECL (c))) - == TREE_VEC)) + if (OMP_ITERATOR_DECL_P (OMP_CLAUSE_DECL (c))) TREE_VALUE (OMP_CLAUSE_DECL (c)) = t; else OMP_CLAUSE_DECL (c) = t; @@ -16823,9 +17048,22 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) case OMP_CLAUSE_MAP: if (OMP_CLAUSE_MAP_IMPLICIT (c) && !implicit_moved) goto move_implicit; + if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_PUSH_MAPPER_NAME + || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POP_MAPPER_NAME) + { + remove = true; + break; + } /* FALLTHRU */ case OMP_CLAUSE_TO: case OMP_CLAUSE_FROM: + if (OMP_CLAUSE_ITERATORS (c) + && c_omp_finish_iterators (OMP_CLAUSE_ITERATORS (c))) + { + t = error_mark_node; + break; + } + /* FALLTHRU */ case OMP_CLAUSE__CACHE_: { using namespace omp_addr_tokenizer; @@ -17554,6 +17792,11 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) pc = &OMP_CLAUSE_CHAIN (c); } + if (grp_start_p + && OMP_CLAUSE_HAS_ITERATORS (*grp_start_p)) + for (tree gc = *grp_start_p; gc; gc = OMP_CLAUSE_CHAIN (gc)) + OMP_CLAUSE_ITERATORS (gc) = OMP_CLAUSE_ITERATORS (*grp_start_p); + if (simdlen && safelen && tree_int_cst_lt (OMP_CLAUSE_SAFELEN_EXPR (safelen), @@ -17763,6 +18006,15 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) return clauses; } +/* Do processing necessary to make CLAUSES well-formed, where CLAUSES result + from implicit instantiation of user-defined mappers (in gimplify.cc). */ + +tree +c_omp_finish_mapper_clauses (tree clauses) +{ + return c_finish_omp_clauses (clauses, C_ORT_OMP); +} + /* Return code to initialize DST with a copy constructor from SRC. C doesn't have copy constructors nor assignment operators, only for _Atomic vars we need to perform __atomic_load from src into a temporary |