aboutsummaryrefslogtreecommitdiff
path: root/gcc/c
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2022-09-05 10:44:56 +0200
committerMartin Liska <mliska@suse.cz>2022-09-05 10:44:56 +0200
commitd8e441f4b8698f38e4564fe1bbe9ff112814ecff (patch)
tree62aac45da0a2358e1ea29a07ab734f607a201e5b /gcc/c
parent4483fe115cef3eea1d64e913816e2d117b38ac73 (diff)
parentca60bd93e216ae0425f790e1d4f4dc4a48763c0e (diff)
downloadgcc-d8e441f4b8698f38e4564fe1bbe9ff112814ecff.zip
gcc-d8e441f4b8698f38e4564fe1bbe9ff112814ecff.tar.gz
gcc-d8e441f4b8698f38e4564fe1bbe9ff112814ecff.tar.bz2
Merge branch 'master' into devel/sphinx
Diffstat (limited to 'gcc/c')
-rw-r--r--gcc/c/ChangeLog95
-rw-r--r--gcc/c/c-convert.cc25
-rw-r--r--gcc/c/c-decl.cc31
-rw-r--r--gcc/c/c-parser.cc213
-rw-r--r--gcc/c/c-tree.h3
-rw-r--r--gcc/c/c-typeck.cc109
6 files changed, 372 insertions, 104 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index a57d62f..a97faa6 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,98 @@
+2022-09-03 Jakub Jelinek <jakub@redhat.com>
+
+ * c-parser.cc (c_parser_omp_clause_name): Handle doacross.
+ (c_parser_omp_clause_depend_sink): Renamed to ...
+ (c_parser_omp_clause_doacross_sink): ... this. Add depend_p argument.
+ Handle parsing of doacross(sink:omp_cur_iteration-1). Use
+ OMP_CLAUSE_DOACROSS_SINK_NEGATIVE instead of
+ OMP_CLAUSE_DEPEND_SINK_NEGATIVE, build OMP_CLAUSE_DOACROSS instead
+ of OMP_CLAUSE_DEPEND and set OMP_CLAUSE_DOACROSS_DEPEND flag on it.
+ (c_parser_omp_clause_depend): Use OMP_CLAUSE_DOACROSS_SINK and
+ OMP_CLAUSE_DOACROSS_SOURCE instead of OMP_CLAUSE_DEPEND_SINK and
+ OMP_CLAUSE_DEPEND_SOURCE, build OMP_CLAUSE_DOACROSS for depend(source)
+ and set OMP_CLAUSE_DOACROSS_DEPEND on it.
+ (c_parser_omp_clause_doacross): New function.
+ (c_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_DOACROSS.
+ (c_parser_omp_depobj): Use OMP_CLAUSE_DEPEND_INVALID instead of
+ OMP_CLAUSE_DEPEND_SOURCE.
+ (c_parser_omp_for_loop): Don't diagnose here linear clause together
+ with ordered with argument.
+ (c_parser_omp_simd): Don't diagnose ordered clause with argument on
+ for simd.
+ (OMP_ORDERED_DEPEND_CLAUSE_MASK): Add PRAGMA_OMP_CLAUSE_DOACROSS.
+ (c_parser_omp_ordered): Handle also doacross and adjust for it
+ diagnostic wording.
+ * c-typeck.cc (c_finish_omp_clauses): Handle OMP_CLAUSE_DOACROSS.
+ Don't handle OMP_CLAUSE_DEPEND_SOURCE and OMP_CLAUSE_DEPEND_SINK.
+
+2022-09-02 David Malcolm <dmalcolm@redhat.com>
+
+ PR c/90885
+ * c-parser.cc (c_parser_string_literal): Clear ret.m_decimal.
+ (c_parser_expr_no_commas): Likewise.
+ (c_parser_conditional_expression): Likewise.
+ (c_parser_binary_expression): Clear m_decimal when popping the
+ stack.
+ (c_parser_unary_expression): Clear ret.m_decimal.
+ (c_parser_has_attribute_expression): Likewise for result.
+ (c_parser_predefined_identifier): Likewise for expr.
+ (c_parser_postfix_expression): Likewise for expr.
+ Set expr.m_decimal when handling a CPP_NUMBER that was a decimal
+ token.
+ * c-tree.h (c_expr::m_decimal): New bitfield.
+ * c-typeck.cc (parser_build_binary_op): Clear result.m_decimal.
+ (parser_build_binary_op): Call check_for_xor_used_as_pow.
+
+2022-09-01 Joseph Myers <joseph@codesourcery.com>
+
+ * c-decl.cc (grokparms): Handle () in a function declaration the
+ same as (void) for C2X.
+
+2022-08-31 Joseph Myers <joseph@codesourcery.com>
+
+ * c-parser.cc (c_parser_label): Pass attributes to do_case.
+ * c-typeck.cc (do_case): Add argument ATTRS. Pass it to
+ c_add_case_label.
+
+2022-08-26 Jakub Jelinek <jakub@redhat.com>
+
+ * c-typeck.cc (convert_arguments): Handle BUILT_IN_ISSIGNALING.
+
+2022-08-25 Marek Polacek <polacek@redhat.com>
+
+ * c-convert.cc (c_convert) <case POINTER_TYPE>: Handle NULLPTR_TYPE.
+ Give a better diagnostic when converting to nullptr_t.
+ * c-decl.cc (c_init_decl_processing): Perform C-specific nullptr
+ initialization.
+ * c-parser.cc (c_parse_init): Maybe OR D_C2X into mask.
+ (c_parser_postfix_expression): Handle RID_NULLPTR.
+ * c-typeck.cc (null_pointer_constant_p): Return true when expr is
+ nullptr_node.
+ (build_unary_op) <case TRUTH_NOT_EXPR>: Handle NULLPTR_TYPE.
+ (build_conditional_expr): Handle the case when the second/third operand
+ is NULLPTR_TYPE and third/second operand is POINTER_TYPE.
+ (convert_for_assignment): Handle converting an expression of type
+ nullptr_t to pointer/bool.
+ (build_binary_op) <case TRUTH_XOR_EXPR>: Handle NULLPTR_TYPE.
+ <case EQ_EXPR>: Handle comparing operands of type nullptr_t.
+
+2022-08-25 Joseph Myers <joseph@codesourcery.com>
+
+ * c-decl.cc (start_decl): Do not diagnose initialization of
+ variable-sized objects here.
+ * c-parser.cc (c_parser_braced_init): Add argument DECL. All
+ callers changed.
+ (c_parser_initializer): Diagnose initialization of variable-sized
+ objects other than with braced initializer.
+ (c_parser_braced_init): Use pedwarn_c11 for empty initializer
+ braces and update diagnostic text. Diagnose initialization of
+ variable-sized objects with nonempty braces.
+ * c-typeck.cc (digest_init): Update diagnostic for initialization
+ of variable-sized objects.
+ (really_start_incremental_init, set_designator)
+ (process_init_element): Update comments.
+ (pop_init_level): Allow scalar empty initializers.
+
2022-08-17 Tobias Burnus <tobias@codesourcery.com>
Chung-Lin Tang <cltang@codesourcery.com>
diff --git a/gcc/c/c-convert.cc b/gcc/c/c-convert.cc
index 18083d5..6e74913 100644
--- a/gcc/c/c-convert.cc
+++ b/gcc/c/c-convert.cc
@@ -133,6 +133,20 @@ c_convert (tree type, tree expr, bool init_const)
(loc, type, c_objc_common_truthvalue_conversion (input_location, expr));
case POINTER_TYPE:
+ /* The type nullptr_t may be converted to a pointer type. The result is
+ a null pointer value. */
+ if (NULLPTR_TYPE_P (TREE_TYPE (e)))
+ {
+ /* To make sure that (void *)nullptr is not a null pointer constant,
+ build_c_cast will create an additional NOP_EXPR around the result
+ of this conversion. */
+ if (TREE_SIDE_EFFECTS (e))
+ ret = build2 (COMPOUND_EXPR, type, e, build_int_cst (type, 0));
+ else
+ ret = build_int_cst (type, 0);
+ goto maybe_fold;
+ }
+ gcc_fallthrough ();
case REFERENCE_TYPE:
ret = convert_to_pointer (type, e);
goto maybe_fold;
@@ -180,7 +194,16 @@ c_convert (tree type, tree expr, bool init_const)
return ret;
}
- error ("conversion to non-scalar type requested");
+ /* If we are converting to nullptr_t, don't say "non-scalar type" because
+ the nullptr_t type is a scalar type. Only nullptr_t shall be converted
+ to nullptr_t. */
+ if (code == NULLPTR_TYPE)
+ {
+ error ("conversion from %qT to %qT", TREE_TYPE (e), type);
+ inform (input_location, "only %qT can be converted to %qT", type, type);
+ }
+ else
+ error ("conversion to non-scalar type requested");
return error_mark_node;
}
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 9e590c6..34f8fed 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -4531,6 +4531,12 @@ c_init_decl_processing (void)
pushdecl (build_decl (UNKNOWN_LOCATION, TYPE_DECL, get_identifier ("_Bool"),
boolean_type_node));
+ /* C-specific nullptr initialization. */
+ record_builtin_type (RID_MAX, "nullptr_t", nullptr_type_node);
+ /* The size and alignment of nullptr_t is the same as for a pointer to
+ character type. */
+ SET_TYPE_ALIGN (nullptr_type_node, GET_MODE_ALIGNMENT (ptr_mode));
+
input_location = save_loc;
make_fname_decl = c_make_fname_decl;
@@ -5180,29 +5186,15 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
initialized = false;
else if (COMPLETE_TYPE_P (TREE_TYPE (decl)))
{
- /* A complete type is ok if size is fixed. */
-
- if (!poly_int_tree_p (TYPE_SIZE (TREE_TYPE (decl)))
- || C_DECL_VARIABLE_SIZE (decl))
- {
- error ("variable-sized object may not be initialized");
- initialized = false;
- }
+ /* A complete type is ok if size is fixed. If the size is
+ variable, an empty initializer is OK and nonempty
+ initializers will be diagnosed in the parser. */
}
else if (TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE)
{
error ("variable %qD has initializer but incomplete type", decl);
initialized = false;
}
- else if (C_DECL_VARIABLE_SIZE (decl))
- {
- /* Although C99 is unclear about whether incomplete arrays
- of VLAs themselves count as VLAs, it does not make
- sense to permit them to be initialized given that
- ordinary VLAs may not be initialized. */
- error ("variable-sized object may not be initialized");
- initialized = false;
- }
}
if (initialized)
@@ -7876,7 +7868,7 @@ grokparms (struct c_arg_info *arg_info, bool funcdef_flag)
error ("%<[*]%> not allowed in other than function prototype scope");
}
- if (arg_types == NULL_TREE && !funcdef_flag
+ if (arg_types == NULL_TREE && !funcdef_flag && !flag_isoc2x
&& !in_system_header_at (input_location))
warning (OPT_Wstrict_prototypes,
"function declaration isn%'t a prototype");
@@ -7904,9 +7896,8 @@ grokparms (struct c_arg_info *arg_info, bool funcdef_flag)
tree parm, type, typelt;
unsigned int parmno;
- /* In C2X, convert () in a function definition to (void). */
+ /* In C2X, convert () to (void). */
if (flag_isoc2x
- && funcdef_flag
&& !arg_types
&& !arg_info->parms)
arg_types = arg_info->types = void_list_node;
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 759f200..65d73a6 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -119,6 +119,8 @@ c_parse_init (void)
mask |= D_CXXONLY;
if (!flag_isoc99)
mask |= D_C99;
+ if (!flag_isoc2x)
+ mask |= D_C2X;
if (flag_no_asm)
{
mask |= D_ASM | D_EXT;
@@ -1523,7 +1525,7 @@ static tree c_parser_simple_asm_expr (c_parser *);
static tree c_parser_gnu_attributes (c_parser *);
static struct c_expr c_parser_initializer (c_parser *, tree);
static struct c_expr c_parser_braced_init (c_parser *, tree, bool,
- struct obstack *);
+ struct obstack *, tree);
static void c_parser_initelt (c_parser *, struct obstack *);
static void c_parser_initval (c_parser *, struct c_expr *,
struct obstack *);
@@ -5220,11 +5222,15 @@ static struct c_expr
c_parser_initializer (c_parser *parser, tree decl)
{
if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
- return c_parser_braced_init (parser, NULL_TREE, false, NULL);
+ return c_parser_braced_init (parser, NULL_TREE, false, NULL, decl);
else
{
struct c_expr ret;
location_t loc = c_parser_peek_token (parser)->location;
+ if (decl != error_mark_node && C_DECL_VARIABLE_SIZE (decl))
+ error_at (loc,
+ "variable-sized object may not be initialized except "
+ "with an empty initializer");
ret = c_parser_expr_no_commas (parser, NULL);
/* This is handled mostly by gimplify.cc, but we have to deal with
not warning about int x = x; as it is a GCC extension to turn off
@@ -5251,11 +5257,12 @@ location_t last_init_list_comma;
compound literal, and NULL_TREE for other initializers and for
nested braced lists. NESTED_P is true for nested braced lists,
false for the list of a compound literal or the list that is the
- top-level initializer in a declaration. */
+ top-level initializer in a declaration. DECL is the declaration for
+ the top-level initializer for a declaration, otherwise NULL_TREE. */
static struct c_expr
c_parser_braced_init (c_parser *parser, tree type, bool nested_p,
- struct obstack *outer_obstack)
+ struct obstack *outer_obstack, tree decl)
{
struct c_expr ret;
struct obstack braced_init_obstack;
@@ -5273,10 +5280,15 @@ c_parser_braced_init (c_parser *parser, tree type, bool nested_p,
really_start_incremental_init (type);
if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
{
- pedwarn (brace_loc, OPT_Wpedantic, "ISO C forbids empty initializer braces");
+ pedwarn_c11 (brace_loc, OPT_Wpedantic,
+ "ISO C forbids empty initializer braces before C2X");
}
else
{
+ if (decl && decl != error_mark_node && C_DECL_VARIABLE_SIZE (decl))
+ error_at (brace_loc,
+ "variable-sized object may not be initialized except "
+ "with an empty initializer");
/* Parse a non-empty initializer list, possibly with a trailing
comma. */
while (true)
@@ -5532,7 +5544,7 @@ c_parser_initval (c_parser *parser, struct c_expr *after,
if (c_parser_next_token_is (parser, CPP_OPEN_BRACE) && !after)
init = c_parser_braced_init (parser, NULL_TREE, true,
- braced_init_obstack);
+ braced_init_obstack, NULL_TREE);
else
{
init = c_parser_expr_no_commas (parser, after);
@@ -5900,14 +5912,14 @@ c_parser_label (c_parser *parser, tree std_attrs)
if (c_parser_next_token_is (parser, CPP_COLON))
{
c_parser_consume_token (parser);
- label = do_case (loc1, exp1, NULL_TREE);
+ label = do_case (loc1, exp1, NULL_TREE, std_attrs);
}
else if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
{
c_parser_consume_token (parser);
exp2 = c_parser_expr_no_commas (parser, NULL).value;
if (c_parser_require (parser, CPP_COLON, "expected %<:%>"))
- label = do_case (loc1, exp1, exp2);
+ label = do_case (loc1, exp1, exp2, std_attrs);
}
else
c_parser_error (parser, "expected %<:%> or %<...%>");
@@ -5916,7 +5928,7 @@ c_parser_label (c_parser *parser, tree std_attrs)
{
c_parser_consume_token (parser);
if (c_parser_require (parser, CPP_COLON, "expected %<:%>"))
- label = do_case (loc1, NULL_TREE, NULL_TREE);
+ label = do_case (loc1, NULL_TREE, NULL_TREE, std_attrs);
}
else
{
@@ -7519,6 +7531,7 @@ c_parser_string_literal (c_parser *parser, bool translate, bool wide_ok)
ret.original_code = STRING_CST;
ret.original_type = NULL_TREE;
set_c_expr_source_range (&ret, get_range_from_loc (line_table, loc));
+ ret.m_decimal = 0;
parser->seen_string_literal = true;
return ret;
}
@@ -7598,6 +7611,7 @@ c_parser_expr_no_commas (c_parser *parser, struct c_expr *after,
ret.value = build_modify_expr (op_location, lhs.value, lhs.original_type,
code, exp_location, rhs.value,
rhs.original_type);
+ ret.m_decimal = 0;
set_c_expr_source_range (&ret, lhs.get_start (), rhs.get_finish ());
if (code == NOP_EXPR)
ret.original_code = MODIFY_EXPR;
@@ -7735,6 +7749,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after,
: NULL);
}
set_c_expr_source_range (&ret, start, exp2.get_finish ());
+ ret.m_decimal = 0;
return ret;
}
@@ -7924,6 +7939,7 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after,
TREE_OPERAND (t, 0) = stack[0].expr.value; \
TREE_OPERAND (t, 1) = stack[1].expr.value; \
stack[0].expr.value = t; \
+ stack[0].expr.m_decimal = 0; \
} \
else \
stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc, \
@@ -8210,6 +8226,7 @@ c_parser_unary_expression (c_parser *parser)
ret.value = build_indirect_ref (combined_loc, op.value, RO_UNARY_STAR);
ret.src_range.m_start = op_loc;
ret.src_range.m_finish = finish;
+ ret.m_decimal = 0;
return ret;
}
case CPP_PLUS:
@@ -8583,6 +8600,7 @@ c_parser_has_attribute_expression (c_parser *parser)
result.value = boolean_false_node;
set_c_expr_source_range (&result, start, finish);
+ result.m_decimal = 0;
return result;
}
@@ -8948,6 +8966,7 @@ c_parser_predefined_identifier (c_parser *parser)
expr.value = fname_decl (loc, c_parser_peek_token (parser)->keyword,
c_parser_peek_token (parser)->value);
set_c_expr_source_range (&expr, loc, loc);
+ expr.m_decimal = 0;
c_parser_consume_token (parser);
return expr;
}
@@ -9026,12 +9045,14 @@ c_parser_postfix_expression (c_parser *parser)
source_range tok_range = c_parser_peek_token (parser)->get_range ();
expr.original_code = ERROR_MARK;
expr.original_type = NULL;
+ expr.m_decimal = 0;
switch (c_parser_peek_token (parser)->type)
{
case CPP_NUMBER:
expr.value = c_parser_peek_token (parser)->value;
set_c_expr_source_range (&expr, tok_range);
loc = c_parser_peek_token (parser)->location;
+ expr.m_decimal = c_parser_peek_token (parser)->flags & DECIMAL_INT;
c_parser_consume_token (parser);
if (TREE_CODE (expr.value) == FIXED_CST
&& !targetm.fixed_point_supported_p ())
@@ -10243,6 +10264,14 @@ c_parser_postfix_expression (c_parser *parser)
"%<depend%> clause");
expr.set_error ();
break;
+ /* C23 'nullptr' literal. */
+ case RID_NULLPTR:
+ c_parser_consume_token (parser);
+ expr.value = nullptr_node;
+ set_c_expr_source_range (&expr, tok_range);
+ pedwarn_c11 (loc, OPT_Wpedantic,
+ "ISO C does not support %qs before C2X", "nullptr");
+ break;
default:
c_parser_error (parser, "expected expression");
expr.set_error ();
@@ -10307,7 +10336,7 @@ c_parser_postfix_expression_after_paren_type (c_parser *parser,
error_at (type_loc, "compound literal has variable size");
type = error_mark_node;
}
- init = c_parser_braced_init (parser, type, false, NULL);
+ init = c_parser_braced_init (parser, type, false, NULL, NULL_TREE);
finish_init ();
maybe_warn_string_init (type_loc, type, init);
@@ -12794,6 +12823,8 @@ c_parser_omp_clause_name (c_parser *parser)
result = PRAGMA_OMP_CLAUSE_DEVICE_TYPE;
else if (!strcmp ("dist_schedule", p))
result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE;
+ else if (!strcmp ("doacross", p))
+ result = PRAGMA_OMP_CLAUSE_DOACROSS;
break;
case 'e':
if (!strcmp ("enter", p))
@@ -15942,8 +15973,8 @@ c_parser_omp_clause_simdlen (c_parser *parser, tree list)
*/
static tree
-c_parser_omp_clause_depend_sink (c_parser *parser, location_t clause_loc,
- tree list)
+c_parser_omp_clause_doacross_sink (c_parser *parser, location_t clause_loc,
+ tree list, bool depend_p)
{
tree vec = NULL;
if (c_parser_next_token_is_not (parser, CPP_NAME)
@@ -15953,6 +15984,31 @@ c_parser_omp_clause_depend_sink (c_parser *parser, location_t clause_loc,
return list;
}
+ if (!depend_p)
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "omp_cur_iteration") == 0
+ && c_parser_peek_2nd_token (parser)->type == CPP_MINUS
+ && c_parser_peek_nth_token (parser, 3)->type == CPP_NUMBER
+ && c_parser_peek_nth_token (parser, 4)->type == CPP_CLOSE_PAREN)
+ {
+ tree val = c_parser_peek_nth_token (parser, 3)->value;
+ if (integer_onep (val)
+ && comptypes (TREE_TYPE (val), integer_type_node))
+ {
+ c_parser_consume_token (parser);
+ c_parser_consume_token (parser);
+ c_parser_consume_token (parser);
+ tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DOACROSS);
+ OMP_CLAUSE_DOACROSS_KIND (u) = OMP_CLAUSE_DOACROSS_SINK;
+ OMP_CLAUSE_CHAIN (u) = list;
+ return u;
+ }
+ }
+ }
+
+
+
while (c_parser_next_token_is (parser, CPP_NAME)
&& c_parser_peek_token (parser)->id_kind == C_ID_ID)
{
@@ -15998,7 +16054,7 @@ c_parser_omp_clause_depend_sink (c_parser *parser, location_t clause_loc,
{
vec = tree_cons (addend, t, vec);
if (neg)
- OMP_CLAUSE_DEPEND_SINK_NEGATIVE (vec) = 1;
+ OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (vec) = 1;
}
if (c_parser_next_token_is_not (parser, CPP_COMMA)
@@ -16012,8 +16068,9 @@ c_parser_omp_clause_depend_sink (c_parser *parser, location_t clause_loc,
if (vec == NULL_TREE)
return list;
- tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DEPEND);
- OMP_CLAUSE_DEPEND_KIND (u) = OMP_CLAUSE_DEPEND_SINK;
+ tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DOACROSS);
+ OMP_CLAUSE_DOACROSS_KIND (u) = OMP_CLAUSE_DOACROSS_SINK;
+ OMP_CLAUSE_DOACROSS_DEPEND (u) = depend_p;
OMP_CLAUSE_DECL (u) = nreverse (vec);
OMP_CLAUSE_CHAIN (u) = list;
return u;
@@ -16205,6 +16262,7 @@ c_parser_omp_clause_depend (c_parser *parser, tree list)
{
location_t clause_loc = c_parser_peek_token (parser)->location;
enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_LAST;
+ enum omp_clause_doacross_kind dkind = OMP_CLAUSE_DOACROSS_LAST;
tree nl, c, iterators = NULL_TREE;
matching_parens parens;
@@ -16236,9 +16294,9 @@ c_parser_omp_clause_depend (c_parser *parser, tree list)
else if (strcmp ("depobj", p) == 0)
kind = OMP_CLAUSE_DEPEND_DEPOBJ;
else if (strcmp ("sink", p) == 0)
- kind = OMP_CLAUSE_DEPEND_SINK;
+ dkind = OMP_CLAUSE_DOACROSS_SINK;
else if (strcmp ("source", p) == 0)
- kind = OMP_CLAUSE_DEPEND_SOURCE;
+ dkind = OMP_CLAUSE_DOACROSS_SOURCE;
else
goto invalid_kind;
break;
@@ -16248,18 +16306,20 @@ c_parser_omp_clause_depend (c_parser *parser, tree list)
c_parser_consume_token (parser);
if (iterators
- && (kind == OMP_CLAUSE_DEPEND_SOURCE || kind == OMP_CLAUSE_DEPEND_SINK))
+ && (dkind == OMP_CLAUSE_DOACROSS_SOURCE
+ || dkind == OMP_CLAUSE_DOACROSS_SINK))
{
pop_scope ();
error_at (clause_loc, "%<iterator%> modifier incompatible with %qs",
- kind == OMP_CLAUSE_DEPEND_SOURCE ? "source" : "sink");
+ dkind == OMP_CLAUSE_DOACROSS_SOURCE ? "source" : "sink");
iterators = NULL_TREE;
}
- if (kind == OMP_CLAUSE_DEPEND_SOURCE)
+ if (dkind == OMP_CLAUSE_DOACROSS_SOURCE)
{
- c = build_omp_clause (clause_loc, OMP_CLAUSE_DEPEND);
- OMP_CLAUSE_DEPEND_KIND (c) = kind;
+ c = build_omp_clause (clause_loc, OMP_CLAUSE_DOACROSS);
+ OMP_CLAUSE_DOACROSS_KIND (c) = dkind;
+ OMP_CLAUSE_DOACROSS_DEPEND (c) = 1;
OMP_CLAUSE_DECL (c) = NULL_TREE;
OMP_CLAUSE_CHAIN (c) = list;
parens.skip_until_found_close (parser);
@@ -16269,8 +16329,8 @@ c_parser_omp_clause_depend (c_parser *parser, tree list)
if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
goto resync_fail;
- if (kind == OMP_CLAUSE_DEPEND_SINK)
- nl = c_parser_omp_clause_depend_sink (parser, clause_loc, list);
+ if (dkind == OMP_CLAUSE_DOACROSS_SINK)
+ nl = c_parser_omp_clause_doacross_sink (parser, clause_loc, list, true);
else
{
nl = c_parser_omp_variable_list (parser, clause_loc,
@@ -16306,6 +16366,65 @@ c_parser_omp_clause_depend (c_parser *parser, tree list)
return list;
}
+/* OpenMP 5.2:
+ doacross ( source : )
+ doacross ( source : omp_cur_iteration )
+
+ doacross ( sink : vec )
+ doacross ( sink : omp_cur_iteration - logical_iteration ) */
+
+static tree
+c_parser_omp_clause_doacross (c_parser *parser, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ enum omp_clause_doacross_kind kind = OMP_CLAUSE_DOACROSS_LAST;
+ tree nl;
+ const char *p;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return list;
+
+ if (c_parser_next_token_is_not (parser, CPP_NAME))
+ goto invalid_kind;
+
+ p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp ("sink", p) == 0)
+ kind = OMP_CLAUSE_DOACROSS_SINK;
+ else if (strcmp ("source", p) == 0)
+ kind = OMP_CLAUSE_DOACROSS_SOURCE;
+ else
+ goto invalid_kind;
+
+ c_parser_consume_token (parser);
+
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ goto resync_fail;
+
+ if (kind == OMP_CLAUSE_DOACROSS_SOURCE)
+ {
+ if (c_parser_next_token_is (parser, CPP_NAME)
+ && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value),
+ "omp_cur_iteration") == 0)
+ c_parser_consume_token (parser);
+ nl = build_omp_clause (clause_loc, OMP_CLAUSE_DOACROSS);
+ OMP_CLAUSE_DOACROSS_KIND (nl) = OMP_CLAUSE_DOACROSS_SOURCE;
+ OMP_CLAUSE_DECL (nl) = NULL_TREE;
+ OMP_CLAUSE_CHAIN (nl) = list;
+ }
+ else
+ nl = c_parser_omp_clause_doacross_sink (parser, clause_loc, list, false);
+
+ parens.skip_until_found_close (parser);
+ return nl;
+
+ invalid_kind:
+ c_parser_error (parser, "invalid doacross kind");
+ resync_fail:
+ parens.skip_until_found_close (parser);
+ return list;
+}
+
/* OpenMP 4.0:
map ( map-kind: variable-list )
map ( variable-list )
@@ -17223,6 +17342,10 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
clauses = c_parser_omp_clause_depend (parser, clauses);
c_name = "depend";
break;
+ case PRAGMA_OMP_CLAUSE_DOACROSS:
+ clauses = c_parser_omp_clause_doacross (parser, clauses);
+ c_name = "doacross";
+ break;
case PRAGMA_OMP_CLAUSE_MAP:
clauses = c_parser_omp_clause_map (parser, clauses);
c_name = "map";
@@ -19167,7 +19290,7 @@ c_parser_omp_depobj (c_parser *parser)
parens.skip_until_found_close (parser);
tree clause = NULL_TREE;
- enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_SOURCE;
+ enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INVALID;
location_t c_loc = c_parser_peek_token (parser)->location;
if (c_parser_next_token_is (parser, CPP_NAME))
{
@@ -19206,7 +19329,7 @@ c_parser_omp_depobj (c_parser *parser)
else if (!strcmp ("inoutset", p2))
kind = OMP_CLAUSE_DEPEND_INOUTSET;
}
- if (kind == OMP_CLAUSE_DEPEND_SOURCE)
+ if (kind == OMP_CLAUSE_DEPEND_INVALID)
{
clause = error_mark_node;
error_at (c2_loc, "expected %<in%>, %<out%>, %<inout%>, "
@@ -19218,7 +19341,7 @@ c_parser_omp_depobj (c_parser *parser)
clause = error_mark_node;
}
}
- if (!clause && kind == OMP_CLAUSE_DEPEND_SOURCE)
+ if (!clause && kind == OMP_CLAUSE_DEPEND_INVALID)
{
clause = error_mark_node;
error_at (c_loc, "expected %<depend%>, %<destroy%> or %<update%> clause");
@@ -19417,19 +19540,6 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
= build_int_cst (NULL_TREE, collapse);
ordered = collapse;
}
- if (ordered)
- {
- for (tree *pc = &clauses; *pc; )
- if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_LINEAR)
- {
- error_at (OMP_CLAUSE_LOCATION (*pc),
- "%<linear%> clause may not be specified together "
- "with %<ordered%> clause with a parameter");
- *pc = OMP_CLAUSE_CHAIN (*pc);
- }
- else
- pc = &OMP_CLAUSE_CHAIN (*pc);
- }
gcc_assert (tiling || (collapse >= 1 && ordered >= 0));
count = ordered ? ordered : collapse;
@@ -19867,15 +19977,6 @@ c_parser_omp_simd (location_t loc, c_parser *parser,
{
omp_split_clauses (loc, OMP_SIMD, mask, clauses, cclauses);
clauses = cclauses[C_OMP_CLAUSE_SPLIT_SIMD];
- tree c = omp_find_clause (cclauses[C_OMP_CLAUSE_SPLIT_FOR],
- OMP_CLAUSE_ORDERED);
- if (c && OMP_CLAUSE_ORDERED_EXPR (c))
- {
- error_at (OMP_CLAUSE_LOCATION (c),
- "%<ordered%> clause with parameter may not be specified "
- "on %qs construct", p_name);
- OMP_CLAUSE_ORDERED_EXPR (c) = NULL_TREE;
- }
}
block = c_begin_compound_stmt (true);
@@ -20114,14 +20215,18 @@ c_parser_omp_masked (location_t loc, c_parser *parser,
# pragma omp ordered ordered-clauses new-line
structured-block
- # pragma omp ordered depend-clauses new-line */
+ # pragma omp ordered depend-clauses new-line
+
+ OpenMP 5.2
+ # pragma omp ordered doacross-clauses new-line */
#define OMP_ORDERED_CLAUSE_MASK \
( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREADS) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMD))
#define OMP_ORDERED_DEPEND_CLAUSE_MASK \
- (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DOACROSS))
static bool
c_parser_omp_ordered (c_parser *parser, enum pragma_context context,
@@ -20141,7 +20246,7 @@ c_parser_omp_ordered (c_parser *parser, enum pragma_context context,
{
const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
- if (!strcmp ("depend", p))
+ if (!strcmp ("depend", p) || !strcmp ("doacross", p))
{
if (!flag_openmp) /* flag_openmp_simd */
{
@@ -20151,8 +20256,8 @@ c_parser_omp_ordered (c_parser *parser, enum pragma_context context,
if (context == pragma_stmt)
{
error_at (loc,
- "%<#pragma omp ordered%> with %<depend%> clause may "
- "only be used in compound statements");
+ "%<#pragma omp ordered%> with %qs clause may "
+ "only be used in compound statements", p);
c_parser_skip_to_pragma_eol (parser, false);
return true;
}
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index e655afd..b4231a1 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -147,6 +147,9 @@ struct c_expr
etc), so we stash a copy here. */
source_range src_range;
+ /* True if this was directly from a decimal constant token. */
+ bool m_decimal : 1;
+
/* Access to the first and last locations within the source spelling
of this expression. */
location_t get_start () const { return src_range.m_start; }
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index de8780a..9ada5d2 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -133,6 +133,13 @@ null_pointer_constant_p (const_tree expr)
/* This should really operate on c_expr structures, but they aren't
yet available everywhere required. */
tree type = TREE_TYPE (expr);
+
+ /* An integer constant expression with the value 0, such an expression
+ cast to type void*, or the predefined constant nullptr, are a null
+ pointer constant. */
+ if (expr == nullptr_node)
+ return true;
+
return (TREE_CODE (expr) == INTEGER_CST
&& !TREE_OVERFLOW (expr)
&& integer_zerop (expr)
@@ -3546,6 +3553,7 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist,
case BUILT_IN_ISINF_SIGN:
case BUILT_IN_ISNAN:
case BUILT_IN_ISNORMAL:
+ case BUILT_IN_ISSIGNALING:
case BUILT_IN_FPCLASSIFY:
type_generic_remove_excess_precision = true;
break;
@@ -3821,6 +3829,7 @@ parser_build_binary_op (location_t location, enum tree_code code,
struct c_expr arg1, struct c_expr arg2)
{
struct c_expr result;
+ result.m_decimal = 0;
enum tree_code code1 = arg1.original_code;
enum tree_code code2 = arg2.original_code;
@@ -3978,6 +3987,14 @@ parser_build_binary_op (location_t location, enum tree_code code,
"comparison between %qT and %qT",
type1, type2);
+ if (warn_xor_used_as_pow
+ && code == BIT_XOR_EXPR
+ && arg1.m_decimal
+ && arg2.m_decimal)
+ check_for_xor_used_as_pow (arg1.get_location (), arg1.value,
+ location,
+ arg2.value);
+
return result;
}
@@ -4575,7 +4592,7 @@ build_unary_op (location_t location, enum tree_code code, tree xarg,
case TRUTH_NOT_EXPR:
if (typecode != INTEGER_TYPE && typecode != FIXED_POINT_TYPE
&& typecode != REAL_TYPE && typecode != POINTER_TYPE
- && typecode != COMPLEX_TYPE)
+ && typecode != COMPLEX_TYPE && typecode != NULLPTR_TYPE)
{
error_at (location,
"wrong type argument to unary exclamation mark");
@@ -5515,6 +5532,13 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp,
}
result_type = type2;
}
+ /* 6.5.15: "if one is a null pointer constant (other than a pointer) or has
+ type nullptr_t and the other is a pointer, the result type is the pointer
+ type." */
+ else if (code1 == NULLPTR_TYPE && code2 == POINTER_TYPE)
+ result_type = type2;
+ else if (code1 == POINTER_TYPE && code2 == NULLPTR_TYPE)
+ result_type = type1;
if (!result_type)
{
@@ -7613,12 +7637,13 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
error_at (location, msg);
return error_mark_node;
}
- else if (codel == POINTER_TYPE && coder == INTEGER_TYPE)
+ else if (codel == POINTER_TYPE
+ && (coder == INTEGER_TYPE || coder == NULLPTR_TYPE))
{
- /* An explicit constant 0 can convert to a pointer,
- or one that results from arithmetic, even including
- a cast to integer type. */
- if (!null_pointer_constant)
+ /* An explicit constant 0 or type nullptr_t can convert to a pointer,
+ or one that results from arithmetic, even including a cast to
+ integer type. */
+ if (!null_pointer_constant && coder != NULLPTR_TYPE)
switch (errtype)
{
case ic_argpass:
@@ -7691,7 +7716,10 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
return convert (type, rhs);
}
- else if (codel == BOOLEAN_TYPE && coder == POINTER_TYPE)
+ else if (codel == BOOLEAN_TYPE
+ /* The type nullptr_t may be converted to bool. The
+ result is false. */
+ && (coder == POINTER_TYPE || coder == NULLPTR_TYPE))
{
tree ret;
bool save = in_late_binary_op;
@@ -8291,7 +8319,9 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype,
if (COMPLETE_TYPE_P (type) && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
{
- error_init (init_loc, "variable-sized object may not be initialized");
+ error_init (init_loc,
+ "variable-sized object may not be initialized except "
+ "with an empty initializer");
return error_mark_node;
}
@@ -8641,8 +8671,9 @@ really_start_incremental_init (tree type)
constructor_max_index = integer_minus_one_node;
/* constructor_max_index needs to be an INTEGER_CST. Attempts
- to initialize VLAs will cause a proper error; avoid tree
- checking errors as well by setting a safe value. */
+ to initialize VLAs with a nonempty initializer will cause a
+ proper error; avoid tree checking errors as well by setting a
+ safe value. */
if (constructor_max_index
&& TREE_CODE (constructor_max_index) != INTEGER_CST)
constructor_max_index = integer_minus_one_node;
@@ -9024,12 +9055,14 @@ pop_init_level (location_t loc, int implicit,
&& !gnu_vector_type_p (constructor_type))
{
/* A nonincremental scalar initializer--just return
- the element, after verifying there is just one. */
+ the element, after verifying there is just one.
+ Empty scalar initializers are supported in C2X. */
if (vec_safe_is_empty (constructor_elements))
{
- if (!constructor_erroneous && constructor_type != error_mark_node)
- error_init (loc, "empty scalar initializer");
- ret.value = error_mark_node;
+ if (constructor_erroneous || constructor_type == error_mark_node)
+ ret.value = error_mark_node;
+ else
+ ret.value = build_zero_cst (constructor_type);
}
else if (vec_safe_length (constructor_elements) != 1)
{
@@ -9114,7 +9147,7 @@ set_designator (location_t loc, bool array,
return true;
/* Likewise for an initializer for a variable-size type. Those are
- diagnosed in digest_init. */
+ diagnosed in the parser, except for empty initializer braces. */
if (COMPLETE_TYPE_P (constructor_type)
&& TREE_CODE (TYPE_SIZE (constructor_type)) != INTEGER_CST)
return true;
@@ -10275,7 +10308,7 @@ process_init_element (location_t loc, struct c_expr value, bool implicit,
return;
/* Ignore elements of an initializer for a variable-size type.
- Those are diagnosed in digest_init. */
+ Those are diagnosed in the parser (empty initializer braces are OK). */
if (COMPLETE_TYPE_P (constructor_type)
&& !poly_int_tree_p (TYPE_SIZE (constructor_type)))
return;
@@ -11148,10 +11181,10 @@ c_start_switch (location_t switch_loc,
return add_stmt (cs->switch_stmt);
}
-/* Process a case label at location LOC. */
+/* Process a case label at location LOC, with attributes ATTRS. */
tree
-do_case (location_t loc, tree low_value, tree high_value)
+do_case (location_t loc, tree low_value, tree high_value, tree attrs)
{
tree label = NULL_TREE;
@@ -11187,7 +11220,7 @@ do_case (location_t loc, tree low_value, tree high_value)
label = c_add_case_label (loc, c_switch_stack->cases,
SWITCH_STMT_COND (c_switch_stack->switch_stmt),
- low_value, high_value);
+ low_value, high_value, attrs);
if (label == error_mark_node)
label = NULL_TREE;
return label;
@@ -12107,10 +12140,10 @@ build_binary_op (location_t location, enum tree_code code,
case TRUTH_XOR_EXPR:
if ((code0 == INTEGER_TYPE || code0 == POINTER_TYPE
|| code0 == REAL_TYPE || code0 == COMPLEX_TYPE
- || code0 == FIXED_POINT_TYPE)
+ || code0 == FIXED_POINT_TYPE || code0 == NULLPTR_TYPE)
&& (code1 == INTEGER_TYPE || code1 == POINTER_TYPE
|| code1 == REAL_TYPE || code1 == COMPLEX_TYPE
- || code1 == FIXED_POINT_TYPE))
+ || code1 == FIXED_POINT_TYPE || code1 == NULLPTR_TYPE))
{
/* Result of these operations is always an int,
but that does not mean the operands should be
@@ -12418,6 +12451,27 @@ build_binary_op (location_t location, enum tree_code code,
result_type = type1;
pedwarn (location, 0, "comparison between pointer and integer");
}
+ /* 6.5.9: One of the following shall hold:
+ -- both operands have type nullptr_t; */
+ else if (code0 == NULLPTR_TYPE && code1 == NULLPTR_TYPE)
+ {
+ result_type = nullptr_type_node;
+ /* No need to convert the operands to result_type later. */
+ converted = 1;
+ }
+ /* -- one operand has type nullptr_t and the other is a null pointer
+ constant. We will have to convert the former to the type of the
+ latter, because during gimplification we can't have mismatching
+ comparison operand type. We convert from nullptr_t to the other
+ type, since only nullptr_t can be converted to nullptr_t. Also,
+ even a constant 0 is a null pointer constant, so we may have to
+ create a pointer type from its type. */
+ else if (code0 == NULLPTR_TYPE && null_pointer_constant_p (orig_op1))
+ result_type = (INTEGRAL_TYPE_P (type1)
+ ? build_pointer_type (type1) : type1);
+ else if (code1 == NULLPTR_TYPE && null_pointer_constant_p (orig_op0))
+ result_type = (INTEGRAL_TYPE_P (type0)
+ ? build_pointer_type (type0) : type0);
if ((TREE_CODE (TREE_TYPE (orig_op0)) == BOOLEAN_TYPE
|| truth_value_p (TREE_CODE (orig_op0)))
^ (TREE_CODE (TREE_TYPE (orig_op1)) == BOOLEAN_TYPE
@@ -14789,15 +14843,11 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
}
break;
- case OMP_CLAUSE_DEPEND:
+ case OMP_CLAUSE_DOACROSS:
t = OMP_CLAUSE_DECL (c);
if (t == NULL_TREE)
- {
- gcc_assert (OMP_CLAUSE_DEPEND_KIND (c)
- == OMP_CLAUSE_DEPEND_SOURCE);
- break;
- }
- if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK)
+ break;
+ if (OMP_CLAUSE_DOACROSS_KIND (c) == OMP_CLAUSE_DOACROSS_SINK)
{
gcc_assert (TREE_CODE (t) == TREE_LIST);
for (; t; t = TREE_CHAIN (t))
@@ -14825,7 +14875,8 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
}
break;
}
- /* FALLTHRU */
+ gcc_unreachable ();
+ case OMP_CLAUSE_DEPEND:
case OMP_CLAUSE_AFFINITY:
t = OMP_CLAUSE_DECL (c);
if (TREE_CODE (t) == TREE_LIST