diff options
Diffstat (limited to 'gcc/c')
-rw-r--r-- | gcc/c/ChangeLog | 190 | ||||
-rw-r--r-- | gcc/c/c-decl.cc | 316 | ||||
-rw-r--r-- | gcc/c/c-lang.h | 12 | ||||
-rw-r--r-- | gcc/c/c-objc-common.cc | 5 | ||||
-rw-r--r-- | gcc/c/c-objc-common.h | 12 | ||||
-rw-r--r-- | gcc/c/c-parser.cc | 482 | ||||
-rw-r--r-- | gcc/c/c-tree.h | 12 | ||||
-rw-r--r-- | gcc/c/c-typeck.cc | 423 |
8 files changed, 1176 insertions, 276 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index b7cdd11..cb69b8c 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,193 @@ +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 diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index ad66d7d..7e1c197 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -8943,12 +8943,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); @@ -9430,56 +9432,62 @@ c_update_type_canonical (tree t) } } -/* Verify the argument of the counted_by attribute of the flexible array - member FIELD_DECL is a valid field of the containing structure, - STRUCT_TYPE, Report error and remove this attribute when it's not. */ +/* Verify the argument of the counted_by attribute of each of the + FIELDS_WITH_COUNTED_BY is a valid field of the containing structure, + STRUCT_TYPE, Report error and remove the corresponding attribute + when it's not. */ static void -verify_counted_by_attribute (tree struct_type, tree field_decl) +verify_counted_by_attribute (tree struct_type, + auto_vec<tree> *fields_with_counted_by) { - tree attr_counted_by = lookup_attribute ("counted_by", - DECL_ATTRIBUTES (field_decl)); + for (tree field_decl : *fields_with_counted_by) + { + tree attr_counted_by = lookup_attribute ("counted_by", + DECL_ATTRIBUTES (field_decl)); - if (!attr_counted_by) - return; + if (!attr_counted_by) + continue; - /* If there is an counted_by attribute attached to the field, - verify it. */ + /* If there is an counted_by attribute attached to the field, + verify it. */ - tree fieldname = TREE_VALUE (TREE_VALUE (attr_counted_by)); + tree fieldname = TREE_VALUE (TREE_VALUE (attr_counted_by)); - /* Verify the argument of the attrbute is a valid field of the - containing structure. */ + /* Verify the argument of the attrbute is a valid field of the + containing structure. */ - tree counted_by_field = lookup_field (struct_type, fieldname); + tree counted_by_field = lookup_field (struct_type, fieldname); - /* Error when the field is not found in the containing structure and - remove the corresponding counted_by attribute from the field_decl. */ - if (!counted_by_field) - { - error_at (DECL_SOURCE_LOCATION (field_decl), - "argument %qE to the %<counted_by%> attribute" - " is not a field declaration in the same structure" - " as %qD", fieldname, field_decl); - DECL_ATTRIBUTES (field_decl) - = remove_attribute ("counted_by", DECL_ATTRIBUTES (field_decl)); - } - else - /* Error when the field is not with an integer type. */ - { - while (TREE_CHAIN (counted_by_field)) - counted_by_field = TREE_CHAIN (counted_by_field); - tree real_field = TREE_VALUE (counted_by_field); - - if (!INTEGRAL_TYPE_P (TREE_TYPE (real_field))) + /* Error when the field is not found in the containing structure and + remove the corresponding counted_by attribute from the field_decl. */ + if (!counted_by_field) { error_at (DECL_SOURCE_LOCATION (field_decl), "argument %qE to the %<counted_by%> attribute" - " is not a field declaration with an integer type", - fieldname); + " is not a field declaration in the same structure" + " as %qD", fieldname, field_decl); DECL_ATTRIBUTES (field_decl) = remove_attribute ("counted_by", DECL_ATTRIBUTES (field_decl)); } + else + /* Error when the field is not with an integer type. */ + { + while (TREE_CHAIN (counted_by_field)) + counted_by_field = TREE_CHAIN (counted_by_field); + tree real_field = TREE_VALUE (counted_by_field); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (real_field))) + { + error_at (DECL_SOURCE_LOCATION (field_decl), + "argument %qE to the %<counted_by%> attribute" + " is not a field declaration with an integer type", + fieldname); + DECL_ATTRIBUTES (field_decl) + = remove_attribute ("counted_by", + DECL_ATTRIBUTES (field_decl)); + } + } } } @@ -9554,7 +9562,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, until now.) */ bool saw_named_field = false; - tree counted_by_fam_field = NULL_TREE; + auto_vec<tree> fields_with_counted_by; for (x = fieldlist; x; x = DECL_CHAIN (x)) { /* Whether this field is the last field of the structure or union. @@ -9635,9 +9643,16 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, record it here and do more verification later after the whole structure is complete. */ if (lookup_attribute ("counted_by", DECL_ATTRIBUTES (x))) - counted_by_fam_field = x; + fields_with_counted_by.safe_push (x); } + if (TREE_CODE (TREE_TYPE (x)) == POINTER_TYPE) + /* If there is a counted_by attribute attached to this field, + record it here and do more verification later after the + whole structure is complete. */ + if (lookup_attribute ("counted_by", DECL_ATTRIBUTES (x))) + fields_with_counted_by.safe_push (x); + if (pedantic && TREE_CODE (t) == RECORD_TYPE && flexible_array_type_p (TREE_TYPE (x))) pedwarn (DECL_SOURCE_LOCATION (x), OPT_Wpedantic, @@ -9647,15 +9662,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 +9803,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 +9914,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,12 +9947,12 @@ 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); } - if (counted_by_fam_field) - verify_counted_by_attribute (t, counted_by_fam_field); + if (fields_with_counted_by.length () > 0) + verify_counted_by_attribute (t, &fields_with_counted_by); return t; } @@ -10097,12 +10121,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 +10287,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 +10314,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 +10326,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 */ @@ -13819,6 +13849,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) 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..d574bc7 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)); } 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..0c3e3e2 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 & * + - ~ ! @@ -10572,6 +10624,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 +10664,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 +10724,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 +10732,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 +11146,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 { @@ -19941,11 +20039,11 @@ c_parser_omp_clause_doacross (c_parser *parser, tree list) always | close */ 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)) @@ -19963,12 +20061,26 @@ c_parser_omp_clause_map (c_parser *parser, tree list) if (c_parser_peek_nth_token_raw (parser, pos + 1)->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; for (int pos = 1; pos < map_kind_pos; ++pos) { c_token *tok = c_parser_peek_token (parser); @@ -19989,6 +20101,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 +20112,66 @@ c_parser_omp_clause_map (c_parser *parser, tree list) return list; } close_modifier++; + c_parser_consume_token (parser); + } + 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 +20182,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%>, %<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 +20235,30 @@ 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; + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_SET_MAP_KIND (c, kind); + { + OMP_CLAUSE_SET_MAP_KIND (c, kind); + 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; @@ -21432,7 +21627,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 +22501,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 +26447,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 +26602,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 +26613,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 +26973,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 +27099,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 +28011,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 +28282,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 +28547,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); @@ -29097,7 +29462,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 +29470,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 +29543,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 +29610,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 +29625,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 +29751,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..364f51d 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -765,6 +765,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 +828,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 +888,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,6 +950,10 @@ 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); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 0e1f842..7948106 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. @@ -773,7 +788,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. */ @@ -843,12 +858,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: @@ -912,15 +922,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. */ @@ -1000,8 +1003,14 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) tree composite_type (tree t1, tree t2) { + 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, &cache); + + gcc_checking_assert (comptypes_check_for_composite (n, t1)); + gcc_checking_assert (comptypes_check_for_composite (n, t2)); + return n; } /* Return the type of a conditional expression between pointers to @@ -1014,9 +1023,6 @@ static tree common_pointer_type (tree t1, tree t2) { 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 +1044,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 (TYPE_MAIN_VARIANT (pointed_to_1), + TYPE_MAIN_VARIANT (pointed_to_2)); /* 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 +1453,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 +1615,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 +1817,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); @@ -2019,14 +2042,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 +2055,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 +2076,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 +2114,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 +2133,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 +2160,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 +2178,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); @@ -2928,8 +2922,8 @@ should_suggest_deref_p (tree datum_type) /* For a SUBDATUM field of a structure or union DATUM, generate a REF to the object that represents its counted_by per the attribute counted_by - attached to this field if it's a flexible array member field, otherwise - return NULL_TREE. + attached to this field if it's a flexible array member or a pointer + field, otherwise return NULL_TREE. Set COUNTED_BY_TYPE to the TYPE of the counted_by field. For example, if: @@ -2947,18 +2941,34 @@ should_suggest_deref_p (tree datum_type) */ static tree -build_counted_by_ref (tree datum, tree subdatum, tree *counted_by_type) +build_counted_by_ref (location_t loc, tree datum, tree subdatum, + tree *counted_by_type) { tree type = TREE_TYPE (datum); - if (!c_flexible_array_member_type_p (TREE_TYPE (subdatum))) + tree sub_type = TREE_TYPE (subdatum); + if (!c_flexible_array_member_type_p (sub_type) + && TREE_CODE (sub_type) != POINTER_TYPE) return NULL_TREE; + tree element_type = TREE_TYPE (sub_type); + tree attr_counted_by = lookup_attribute ("counted_by", DECL_ATTRIBUTES (subdatum)); tree counted_by_ref = NULL_TREE; *counted_by_type = NULL_TREE; if (attr_counted_by) { + /* Issue error when the element_type is a structure or + union including a flexible array member. */ + if (RECORD_OR_UNION_TYPE_P (element_type) + && TYPE_INCLUDES_FLEXARRAY (element_type)) + { + error_at (loc, + "%<counted_by%> attribute is not allowed for a pointer to" + " structure or union with flexible array member"); + return error_mark_node; + } + tree field_id = TREE_VALUE (TREE_VALUE (attr_counted_by)); counted_by_ref = build_component_ref (UNKNOWN_LOCATION, @@ -2981,8 +2991,11 @@ build_counted_by_ref (tree datum, tree subdatum, tree *counted_by_type) } /* Given a COMPONENT_REF REF with the location LOC, the corresponding - COUNTED_BY_REF, and the COUNTED_BY_TYPE, generate an INDIRECT_REF - to a call to the internal function .ACCESS_WITH_SIZE. + COUNTED_BY_REF, and the COUNTED_BY_TYPE, generate the corresponding + call to the internal function .ACCESS_WITH_SIZE. + + Generate an INDIRECT_REF to a call to the internal function + .ACCESS_WITH_SIZE. REF @@ -2992,17 +3005,15 @@ build_counted_by_ref (tree datum, tree subdatum, tree *counted_by_type) (TYPE_OF_ARRAY *)0)) NOTE: The return type of this function is the POINTER type pointing - to the original flexible array type. - Then the type of the INDIRECT_REF is the original flexible array type. - - The type of the first argument of this function is a POINTER type - to the original flexible array type. + to the original flexible array type or the original pointer type. + Then the type of the INDIRECT_REF is the original flexible array type + or the original pointer type. The 4th argument of the call is a constant 0 with 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 6th argument of the call is a constant 0 of the same TYPE as + the return type of the call. */ static tree @@ -3010,11 +3021,16 @@ build_access_with_size_for_counted_by (location_t loc, tree ref, tree counted_by_ref, tree counted_by_type) { - 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. */ + gcc_assert (c_flexible_array_member_type_p (TREE_TYPE (ref)) + || TREE_CODE (TREE_TYPE (ref)) == POINTER_TYPE); + bool is_fam = c_flexible_array_member_type_p (TREE_TYPE (ref)); + tree first_param = is_fam ? array_to_pointer_conversion (loc, ref) + : build_unary_op (loc, ADDR_EXPR, ref, false); + + /* The result type of the call is a pointer to the original type + of the ref. */ tree result_type = c_build_pointer_type (TREE_TYPE (ref)); - tree first_param - = c_fully_fold (array_to_pointer_conversion (loc, ref), false, NULL); + first_param = c_fully_fold (first_param, false, NULL); tree second_param = c_fully_fold (counted_by_ref, false, NULL); @@ -3027,7 +3043,7 @@ build_access_with_size_for_counted_by (location_t loc, tree ref, build_int_cst (counted_by_type, 0), build_int_cst (integer_type_node, -1), build_int_cst (result_type, 0)); - /* Wrap the call with an INDIRECT_REF with the flexible array type. */ + /* Wrap the call with an INDIRECT_REF with the original type of the ref. */ call = build1 (INDIRECT_REF, TREE_TYPE (ref), call); SET_EXPR_LOCATION (call, loc); return call; @@ -3045,7 +3061,7 @@ handle_counted_by_for_component_ref (location_t loc, tree ref) tree datum = TREE_OPERAND (ref, 0); tree subdatum = TREE_OPERAND (ref, 1); tree counted_by_type = NULL_TREE; - tree counted_by_ref = build_counted_by_ref (datum, subdatum, + tree counted_by_ref = build_counted_by_ref (loc, datum, subdatum, &counted_by_type); if (counted_by_ref) ref = build_access_with_size_for_counted_by (loc, ref, @@ -3540,7 +3556,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 +3612,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 +3630,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 +3644,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 +3754,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 @@ -7372,10 +7492,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)) { @@ -7413,10 +7530,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; @@ -7427,10 +7541,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) @@ -8187,23 +8298,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); @@ -16840,6 +16942,12 @@ 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: @@ -17780,6 +17888,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 |