aboutsummaryrefslogtreecommitdiff
path: root/gcc/c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c')
-rw-r--r--gcc/c/ChangeLog176
-rw-r--r--gcc/c/c-decl.cc316
-rw-r--r--gcc/c/c-lang.h12
-rw-r--r--gcc/c/c-objc-common.cc5
-rw-r--r--gcc/c/c-objc-common.h12
-rw-r--r--gcc/c/c-parser.cc482
-rw-r--r--gcc/c/c-tree.h12
-rw-r--r--gcc/c/c-typeck.cc423
8 files changed, 1162 insertions, 276 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index b7cdd11..89a3210 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,179 @@
+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