diff options
author | Martin Liska <mliska@suse.cz> | 2022-09-05 10:44:56 +0200 |
---|---|---|
committer | Martin Liska <mliska@suse.cz> | 2022-09-05 10:44:56 +0200 |
commit | d8e441f4b8698f38e4564fe1bbe9ff112814ecff (patch) | |
tree | 62aac45da0a2358e1ea29a07ab734f607a201e5b /gcc/c | |
parent | 4483fe115cef3eea1d64e913816e2d117b38ac73 (diff) | |
parent | ca60bd93e216ae0425f790e1d4f4dc4a48763c0e (diff) | |
download | gcc-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/ChangeLog | 95 | ||||
-rw-r--r-- | gcc/c/c-convert.cc | 25 | ||||
-rw-r--r-- | gcc/c/c-decl.cc | 31 | ||||
-rw-r--r-- | gcc/c/c-parser.cc | 213 | ||||
-rw-r--r-- | gcc/c/c-tree.h | 3 | ||||
-rw-r--r-- | gcc/c/c-typeck.cc | 109 |
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 |