diff options
author | Ian Lance Taylor <iant@golang.org> | 2020-11-10 07:26:18 -0800 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2020-11-10 07:26:18 -0800 |
commit | 8d703821c69062c0cd255787d793e44f1a95d463 (patch) | |
tree | 6b1df9cdc36cc47b6164db69a14bc86a63dc77c6 /gcc/c | |
parent | 9cd320ea6572c577cdf17ce1f9ea5230b166af6d (diff) | |
parent | cf392dbdf17e38026f8e3c0e9af7f5b87f63be56 (diff) | |
download | gcc-8d703821c69062c0cd255787d793e44f1a95d463.zip gcc-8d703821c69062c0cd255787d793e44f1a95d463.tar.gz gcc-8d703821c69062c0cd255787d793e44f1a95d463.tar.bz2 |
Merge from trunk revision cf392dbdf17e38026f8e3c0e9af7f5b87f63be56.
Diffstat (limited to 'gcc/c')
-rw-r--r-- | gcc/c/ChangeLog | 90 | ||||
-rw-r--r-- | gcc/c/c-decl.c | 51 | ||||
-rw-r--r-- | gcc/c/c-parser.c | 605 | ||||
-rw-r--r-- | gcc/c/c-tree.h | 1 | ||||
-rw-r--r-- | gcc/c/c-typeck.c | 204 |
5 files changed, 649 insertions, 302 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 839bfa1..5b0d42c 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,93 @@ +2020-11-07 Martin Uecker <muecker@gwdg.de> + + * c-parser.c (c_parser_label): Implement mixing of labels and code. + (c_parser_all_labels): Likewise. + +2020-11-06 Iain Sandoe <iain@sandoe.co.uk> + + * c-parser.c (c_parser_objc_at_property_declaration): + Improve parsing fidelity. Associate better location info + with @property attributes. Clean up the interface to + objc_add_property_declaration (). + +2020-11-06 Nathan Sidwell <nathan@acm.org> + + * c-decl.c (diagnose_mismatched_decls): Rename + DECL_IS_BUILTIN->DECL_IS_UNDECLARED_BUILTIN. + (warn_if_shadowing, implicitly_declare, names_builtin_p) + (collect_source_refs): Likewise. + * c-typeck.c (inform_declaration, inform_for_arg) + (convert_for_assignment): Likewise. + +2020-11-06 Tobias Burnus <tobias@codesourcery.com> + + * c-parser.c (c_parser_omp_atomic): Add openacc parameter and update + OpenACC matching. + (c_parser_omp_construct): Update call. + +2020-11-04 Jakub Jelinek <jakub@redhat.com> + + PR c++/97670 + * c-typeck.c (c_finish_omp_clauses): Look through array reductions to + find underlying decl to clear in the aligned_head bitmap. + +2020-11-04 Joseph Myers <joseph@codesourcery.com> + + * c-decl.c (handle_nodiscard_attribute): New. + (std_attribute_table): Add nodiscard. + * c-parser.c (c_parser_std_attribute): Expect argument to + nodiscard attribute to be a string. Do not special-case ignoring + nodiscard. + * c-typeck.c (maybe_warn_nodiscard): New. + (build_compound_expr, emit_side_effect_warnings): Call + maybe_warn_nodiscard. + (c_process_expr_stmt, c_finish_stmt_expr): Also call + emit_side_effect_warnings if warn_unused_result. + +2020-10-29 Asher Gordon <AsDaGo@posteo.net> + + * c-typeck.c (free_all_tagged_tu_seen_up_to): Replace free + with XDELETE. + (finish_init): Likewise. + (pop_init_level): Likewise. + +2020-10-28 Joseph Myers <joseph@codesourcery.com> + + * c-decl.c (store_parm_decls_newstyle): Use pedwarn_c11 not + error_at for omitted parameter name. + +2020-10-28 Jakub Jelinek <jakub@redhat.com> + + * c-parser.c (c_parser_omp_clause_name): Handle allocate. + (c_parser_omp_clause_allocate): New function. + (c_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_ALLOCATE. + (OMP_FOR_CLAUSE_MASK, OMP_SECTIONS_CLAUSE_MASK, + OMP_PARALLEL_CLAUSE_MASK, OMP_SINGLE_CLAUSE_MASK, + OMP_TASK_CLAUSE_MASK, OMP_TASKGROUP_CLAUSE_MASK, + OMP_DISTRIBUTE_CLAUSE_MASK, OMP_TEAMS_CLAUSE_MASK, + OMP_TARGET_CLAUSE_MASK, OMP_TASKLOOP_CLAUSE_MASK): Add + PRAGMA_OMP_CLAUSE_ALLOCATE. + * c-typeck.c (c_finish_omp_clauses): Handle OMP_CLAUSE_ALLOCATE. + +2020-10-27 Joseph Myers <joseph@codesourcery.com> + + * c-parser.c (c_parser_std_attribute_specifier): Allow duplicate + standard attributes. + +2020-10-23 Marek Polacek <polacek@redhat.com> + + PR c++/91741 + * c-parser.c (c_parser_binary_expression): Implement -Wsizeof-array-div. + (c_parser_postfix_expression): Set PAREN_SIZEOF_EXPR. + (c_parser_expr_list): Handle PAREN_SIZEOF_EXPR like SIZEOF_EXPR. + * c-tree.h (char_type_p): Declare. + * c-typeck.c (char_type_p): No longer static. + +2020-10-23 Martin Sebor <msebor@redhat.com> + + PR middle-end/97552 + * c-decl.c (get_parm_array_spec): Handle static VLA parameters. + 2020-09-19 Martin Sebor <msebor@redhat.com> PR c/50584 diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 81b9adb..f19c82c 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -2051,7 +2051,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, } } else if (TREE_CODE (olddecl) == FUNCTION_DECL - && DECL_IS_BUILTIN (olddecl)) + && DECL_IS_UNDECLARED_BUILTIN (olddecl)) { /* A conflicting function declaration for a predeclared function that isn't actually built in. Objective C uses @@ -2265,7 +2265,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, built in, newdecl silently overrides olddecl. The latter occur only in Objective C; see also above. (FIXME: Make Objective C use normal builtins.) */ - if (!DECL_IS_BUILTIN (olddecl) + if (!DECL_IS_UNDECLARED_BUILTIN (olddecl) && !DECL_EXTERN_INLINE (olddecl)) { auto_diagnostic_group d; @@ -2978,7 +2978,7 @@ warn_if_shadowing (tree new_decl) || warn_shadow_local || warn_shadow_compatible_local) /* No shadow warnings for internally generated vars. */ - || DECL_IS_BUILTIN (new_decl)) + || DECL_IS_UNDECLARED_BUILTIN (new_decl)) return; /* Is anything being shadowed? Invisible decls do not count. */ @@ -3631,7 +3631,7 @@ implicitly_declare (location_t loc, tree functionid) in the external scope because they're pushed before the file scope gets created. Catch this here and rebind them into the file scope. */ - if (!fndecl_built_in_p (decl) && DECL_IS_BUILTIN (decl)) + if (!fndecl_built_in_p (decl) && DECL_IS_UNDECLARED_BUILTIN (decl)) { bind (functionid, decl, file_scope, /*invisible=*/false, /*nested=*/true, @@ -4400,6 +4400,31 @@ lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc) } +/* Handle the standard [[nodiscard]] attribute. */ + +static tree +handle_nodiscard_attribute (tree *node, tree name, tree /*args*/, + int /*flags*/, bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + { + if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (*node)))) + warning_at (DECL_SOURCE_LOCATION (*node), + OPT_Wattributes, "%qE attribute applied to %qD with void " + "return type", name, *node); + } + else if (RECORD_OR_UNION_TYPE_P (*node) + || TREE_CODE (*node) == ENUMERAL_TYPE) + /* OK */; + else + { + pedwarn (input_location, + OPT_Wattributes, "%qE attribute can only be applied to " + "functions or to structure, union or enumeration types", name); + *no_add_attrs = true; + } + return NULL_TREE; +} /* Table of supported standard (C2x) attributes. */ const struct attribute_spec std_attribute_table[] = { @@ -4411,6 +4436,8 @@ const struct attribute_spec std_attribute_table[] = handle_fallthrough_attribute, NULL }, { "maybe_unused", 0, 0, false, false, false, false, handle_unused_attribute, NULL }, + { "nodiscard", 0, 1, false, false, false, false, + handle_nodiscard_attribute, NULL }, { NULL, 0, 0, false, false, false, false, NULL, NULL } }; @@ -5784,6 +5811,9 @@ get_parm_array_spec (const struct c_parm *parm, tree attrs) continue; } + if (pd->u.array.static_p) + spec += 's'; + if (TREE_CODE (nelts) == INTEGER_CST) { /* Skip all constant bounds except the most significant one. @@ -5796,9 +5826,8 @@ get_parm_array_spec (const struct c_parm *parm, tree attrs) return attrs; char buf[40]; - const char *code = pd->u.array.static_p ? "s" : ""; unsigned HOST_WIDE_INT n = tree_to_uhwi (nelts); - sprintf (buf, "%s%llu", code, (unsigned long long)n); + sprintf (buf, "%llu", (unsigned long long)n); spec += buf; break; } @@ -9628,7 +9657,9 @@ store_parm_decls_newstyle (tree fndecl, const struct c_arg_info *arg_info) warn_if_shadowing (decl); } else - error_at (DECL_SOURCE_LOCATION (decl), "parameter name omitted"); + pedwarn_c11 (DECL_SOURCE_LOCATION (decl), OPT_Wpedantic, + "ISO C does not support omitting parameter names in " + "function definitions before C2X"); } /* Record the parameter list in the function declaration. */ @@ -10469,7 +10500,7 @@ names_builtin_p (const char *name) { tree id = get_identifier (name); if (tree decl = identifier_global_value (id)) - return TREE_CODE (decl) == FUNCTION_DECL && DECL_IS_BUILTIN (decl); + return TREE_CODE (decl) == FUNCTION_DECL && DECL_IS_UNDECLARED_BUILTIN (decl); /* Also detect common reserved C words that aren't strictly built-in functions. */ @@ -12103,12 +12134,12 @@ collect_source_refs (void) { decls = DECL_INITIAL (t); for (decl = BLOCK_VARS (decls); decl; decl = TREE_CHAIN (decl)) - if (!DECL_IS_BUILTIN (decl)) + if (!DECL_IS_UNDECLARED_BUILTIN (decl)) collect_source_ref (DECL_SOURCE_FILE (decl)); } for (decl = BLOCK_VARS (ext_block); decl; decl = TREE_CHAIN (decl)) - if (!DECL_IS_BUILTIN (decl)) + if (!DECL_IS_UNDECLARED_BUILTIN (decl)) collect_source_ref (DECL_SOURCE_FILE (decl)); } diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 7d58356..377914c 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1521,7 +1521,7 @@ static void c_parser_initval (c_parser *, struct c_expr *, struct obstack *); static tree c_parser_compound_statement (c_parser *, location_t * = NULL); static location_t c_parser_compound_statement_nostart (c_parser *); -static void c_parser_label (c_parser *); +static void c_parser_label (c_parser *, tree); static void c_parser_statement (c_parser *, bool *, location_t * = NULL); static void c_parser_statement_after_labels (c_parser *, bool *, vec<tree> * = NULL); @@ -4950,7 +4950,8 @@ c_parser_std_attribute (c_parser *parser, bool for_tm) && attribute_takes_identifier_p (name)); bool require_string = (ns == NULL_TREE - && strcmp (IDENTIFIER_POINTER (name), "deprecated") == 0); + && (strcmp (IDENTIFIER_POINTER (name), "deprecated") == 0 + || strcmp (IDENTIFIER_POINTER (name), "nodiscard") == 0)); TREE_VALUE (attribute) = c_parser_attribute_arguments (parser, takes_identifier, require_string, false); @@ -4960,13 +4961,12 @@ c_parser_std_attribute (c_parser *parser, bool for_tm) parens.require_close (parser); } out: - if (ns == NULL_TREE && !for_tm && !as && !is_attribute_p ("nodiscard", name)) + if (ns == NULL_TREE && !for_tm && !as) { /* An attribute with standard syntax and no namespace specified is a constraint violation if it is not one of the known - standard attributes (of which nodiscard is the only one - without a handler in GCC). Diagnose it here with a pedwarn - and then discard it to prevent a duplicate warning later. */ + standard attributes. Diagnose it here with a pedwarn and + then discard it to prevent a duplicate warning later. */ pedwarn (input_location, OPT_Wattributes, "%qE attribute ignored", name); return error_mark_node; @@ -4977,9 +4977,6 @@ c_parser_std_attribute (c_parser *parser, bool for_tm) static tree c_parser_std_attribute_specifier (c_parser *parser, bool for_tm) { - bool seen_deprecated = false; - bool seen_fallthrough = false; - bool seen_maybe_unused = false; location_t loc = c_parser_peek_token (parser)->location; if (!c_parser_require (parser, CPP_OPEN_SQUARE, "expected %<[%>")) return NULL_TREE; @@ -5005,55 +5002,8 @@ c_parser_std_attribute_specifier (c_parser *parser, bool for_tm) tree attribute = c_parser_std_attribute (parser, for_tm); if (attribute != error_mark_node) { - bool duplicate = false; - tree name = get_attribute_name (attribute); - tree ns = get_attribute_namespace (attribute); - if (ns == NULL_TREE) - { - /* Some standard attributes may appear at most once in - each attribute list. Diagnose duplicates and remove - them from the list to avoid subsequent diagnostics - such as the more general one for multiple - "fallthrough" attributes in the same place (including - in separate attribute lists in the same attribute - specifier sequence, which is not a constraint - violation). */ - if (is_attribute_p ("deprecated", name)) - { - if (seen_deprecated) - { - error ("attribute %<deprecated%> can appear at most " - "once in an attribute-list"); - duplicate = true; - } - seen_deprecated = true; - } - else if (is_attribute_p ("fallthrough", name)) - { - if (seen_fallthrough) - { - error ("attribute %<fallthrough%> can appear at most " - "once in an attribute-list"); - duplicate = true; - } - seen_fallthrough = true; - } - else if (is_attribute_p ("maybe_unused", name)) - { - if (seen_maybe_unused) - { - error ("attribute %<maybe_unused%> can appear at most " - "once in an attribute-list"); - duplicate = true; - } - seen_maybe_unused = true; - } - } - if (!duplicate) - { - TREE_CHAIN (attribute) = attributes; - attributes = attribute; - } + TREE_CHAIN (attribute) = attributes; + attributes = attribute; } if (c_parser_next_token_is_not (parser, CPP_COMMA)) break; @@ -5573,7 +5523,7 @@ c_parser_initval (c_parser *parser, struct c_expr *after, } /* Parse a compound statement (possibly a function body) (C90 6.6.2, - C99 6.8.2, C11 6.8.2). + C99 6.8.2, C11 6.8.2, C2X 6.8.2). compound-statement: { block-item-list[opt] } @@ -5584,6 +5534,7 @@ c_parser_initval (c_parser *parser, struct c_expr *after, block-item-list block-item block-item: + label nested-declaration statement @@ -5724,7 +5675,7 @@ c_parser_compound_statement_nostart (c_parser *parser) { location_t loc = c_parser_peek_token (parser)->location; loc = expansion_point_location_if_in_system_header (loc); - /* Standard attributes may start a statement or a declaration. */ + /* Standard attributes may start a label, statement or declaration. */ bool have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, 1); tree std_attrs = NULL_TREE; @@ -5735,7 +5686,6 @@ c_parser_compound_statement_nostart (c_parser *parser) || (c_parser_next_token_is (parser, CPP_NAME) && c_parser_peek_2nd_token (parser)->type == CPP_COLON)) { - c_warn_unused_attributes (std_attrs); if (c_parser_next_token_is_keyword (parser, RID_CASE)) label_loc = c_parser_peek_2nd_token (parser)->location; else @@ -5743,27 +5693,31 @@ c_parser_compound_statement_nostart (c_parser *parser) last_label = true; last_stmt = false; mark_valid_location_for_stdc_pragma (false); - c_parser_label (parser); + c_parser_label (parser, std_attrs); } - else if (!last_label - && (c_parser_next_tokens_start_declaration (parser) - || (have_std_attrs - && c_parser_next_token_is (parser, CPP_SEMICOLON)))) + else if (c_parser_next_tokens_start_declaration (parser) + || (have_std_attrs + && c_parser_next_token_is (parser, CPP_SEMICOLON))) { - last_label = false; + if (last_label) + pedwarn_c11 (c_parser_peek_token (parser)->location, OPT_Wpedantic, + "a label can only be part of a statement and " + "a declaration is not a statement"); + mark_valid_location_for_stdc_pragma (false); bool fallthru_attr_p = false; c_parser_declaration_or_fndef (parser, true, !have_std_attrs, true, true, true, NULL, vNULL, have_std_attrs, std_attrs, NULL, &fallthru_attr_p); + if (last_stmt && !fallthru_attr_p) pedwarn_c90 (loc, OPT_Wdeclaration_after_statement, "ISO C90 forbids mixed declarations and code"); last_stmt = fallthru_attr_p; + last_label = false; } - else if (!last_label - && c_parser_next_token_is_keyword (parser, RID_EXTENSION)) + else if (c_parser_next_token_is_keyword (parser, RID_EXTENSION)) { /* __extension__ can start a declaration, but is also an unary operator that can start an expression. Consume all @@ -5846,7 +5800,7 @@ c_parser_compound_statement_nostart (c_parser *parser) parser->error = false; } if (last_label) - error_at (label_loc, "label at end of compound statement"); + pedwarn_c11 (label_loc, OPT_Wpedantic, "label at end of compound statement"); location_t endloc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); /* Restore the value we started with. */ @@ -5862,19 +5816,29 @@ c_parser_compound_statement_nostart (c_parser *parser) static void c_parser_all_labels (c_parser *parser) { + tree std_attrs = NULL; if (c_parser_nth_token_starts_std_attributes (parser, 1)) { - tree std_attrs = c_parser_std_attribute_specifier_sequence (parser); + std_attrs = c_parser_std_attribute_specifier_sequence (parser); if (c_parser_next_token_is (parser, CPP_SEMICOLON)) c_parser_error (parser, "expected statement"); - else - c_warn_unused_attributes (std_attrs); } while (c_parser_next_token_is_keyword (parser, RID_CASE) || c_parser_next_token_is_keyword (parser, RID_DEFAULT) || (c_parser_next_token_is (parser, CPP_NAME) && c_parser_peek_2nd_token (parser)->type == CPP_COLON)) - c_parser_label (parser); + { + c_parser_label (parser, std_attrs); + std_attrs = NULL; + if (c_parser_nth_token_starts_std_attributes (parser, 1)) + { + std_attrs = c_parser_std_attribute_specifier_sequence (parser); + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + c_parser_error (parser, "expected statement"); + } + } + if (std_attrs) + c_warn_unused_attributes (std_attrs); } /* Parse a label (C90 6.6.1, C99 6.8.1, C11 6.8.1). @@ -5896,9 +5860,8 @@ c_parser_all_labels (c_parser *parser) in the caller, to distinguish statements from declarations. Any attribute-specifier-sequence after the label is parsed in this function. */ - static void -c_parser_label (c_parser *parser) +c_parser_label (c_parser *parser, tree std_attrs) { location_t loc1 = c_parser_peek_token (parser)->location; tree label = NULL_TREE; @@ -5948,8 +5911,13 @@ c_parser_label (c_parser *parser) if (tlab) { decl_attributes (&tlab, attrs, 0); + decl_attributes (&tlab, std_attrs, 0); label = add_stmt (build_stmt (loc1, LABEL_EXPR, tlab)); } + if (attrs + && c_parser_next_tokens_start_declaration (parser)) + warning_at (loc2, OPT_Wattributes, "GNU-style attribute between" + " label and declaration appertains to the label"); } if (label) { @@ -5957,55 +5925,6 @@ c_parser_label (c_parser *parser) FALLTHROUGH_LABEL_P (LABEL_EXPR_LABEL (label)) = fallthrough_p; else FALLTHROUGH_LABEL_P (CASE_LABEL (label)) = fallthrough_p; - - /* Standard attributes are only allowed here if they start a - statement, not a declaration (including the case of an - attribute-declaration with only attributes). */ - bool have_std_attrs - = c_parser_nth_token_starts_std_attributes (parser, 1); - tree std_attrs = NULL_TREE; - if (have_std_attrs) - std_attrs = c_parser_std_attribute_specifier_sequence (parser); - - /* Allow '__attribute__((fallthrough));'. */ - if (!have_std_attrs - && c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) - { - location_t loc = c_parser_peek_token (parser)->location; - tree attrs = c_parser_gnu_attributes (parser); - if (attribute_fallthrough_p (attrs)) - { - if (c_parser_next_token_is (parser, CPP_SEMICOLON)) - { - tree fn = build_call_expr_internal_loc (loc, - IFN_FALLTHROUGH, - void_type_node, 0); - add_stmt (fn); - } - else - warning_at (loc, OPT_Wattributes, "%<fallthrough%> attribute " - "not followed by %<;%>"); - } - else if (attrs != NULL_TREE) - warning_at (loc, OPT_Wattributes, "only attribute %<fallthrough%>" - " can be applied to a null statement"); - } - if (c_parser_next_tokens_start_declaration (parser) - || (have_std_attrs - && c_parser_next_token_is (parser, CPP_SEMICOLON))) - { - error_at (c_parser_peek_token (parser)->location, - "a label can only be part of a statement and " - "a declaration is not a statement"); - c_parser_declaration_or_fndef (parser, /*fndef_ok*/ false, - /*static_assert_ok*/ true, - /*empty_ok*/ true, /*nested*/ true, - /*start_attr_ok*/ true, NULL, - vNULL, have_std_attrs, std_attrs); - } - else if (std_attrs) - /* Nonempty attributes on the following statement are ignored. */ - c_warn_unused_attributes (std_attrs); } } @@ -7876,7 +7795,7 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after, enum tree_code op; /* The source location of this operation. */ location_t loc; - /* The sizeof argument if expr.original_code == SIZEOF_EXPR. */ + /* The sizeof argument if expr.original_code == {PAREN_,}SIZEOF_EXPR. */ tree sizeof_arg; } stack[NUM_PRECS]; int sp; @@ -7894,9 +7813,11 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after, c_inhibit_evaluation_warnings -= (stack[sp - 1].expr.value \ == truthvalue_true_node); \ break; \ - case TRUNC_DIV_EXPR: \ - if (stack[sp - 1].expr.original_code == SIZEOF_EXPR \ - && stack[sp].expr.original_code == SIZEOF_EXPR) \ + case TRUNC_DIV_EXPR: \ + if ((stack[sp - 1].expr.original_code == SIZEOF_EXPR \ + || stack[sp - 1].expr.original_code == PAREN_SIZEOF_EXPR) \ + && (stack[sp].expr.original_code == SIZEOF_EXPR \ + || stack[sp].expr.original_code == PAREN_SIZEOF_EXPR)) \ { \ tree type0 = stack[sp - 1].sizeof_arg; \ tree type1 = stack[sp].sizeof_arg; \ @@ -7910,18 +7831,23 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after, && !(TREE_CODE (first_arg) == PARM_DECL \ && C_ARRAY_PARAMETER (first_arg) \ && warn_sizeof_array_argument)) \ - { \ - auto_diagnostic_group d; \ - if (warning_at (stack[sp].loc, OPT_Wsizeof_pointer_div, \ - "division %<sizeof (%T) / sizeof (%T)%> " \ - "does not compute the number of array " \ - "elements", \ - type0, type1)) \ - if (DECL_P (first_arg)) \ - inform (DECL_SOURCE_LOCATION (first_arg), \ - "first %<sizeof%> operand was declared here"); \ - } \ - } \ + { \ + auto_diagnostic_group d; \ + if (warning_at (stack[sp].loc, OPT_Wsizeof_pointer_div, \ + "division %<sizeof (%T) / sizeof (%T)%> " \ + "does not compute the number of array " \ + "elements", \ + type0, type1)) \ + if (DECL_P (first_arg)) \ + inform (DECL_SOURCE_LOCATION (first_arg), \ + "first %<sizeof%> operand was declared here"); \ + } \ + else if (TREE_CODE (type0) == ARRAY_TYPE \ + && !char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type0))) \ + && stack[sp].expr.original_code != PAREN_SIZEOF_EXPR) \ + maybe_warn_sizeof_array_div (stack[sp].loc, first_arg, type0, \ + stack[sp].sizeof_arg, type1); \ + } \ break; \ default: \ break; \ @@ -9177,6 +9103,9 @@ c_parser_postfix_expression (c_parser *parser) if (expr.original_code != C_MAYBE_CONST_EXPR && expr.original_code != SIZEOF_EXPR) expr.original_code = ERROR_MARK; + /* Remember that we saw ( ) around the sizeof. */ + if (expr.original_code == SIZEOF_EXPR) + expr.original_code = PAREN_SIZEOF_EXPR; /* Don't change EXPR.ORIGINAL_TYPE. */ location_t loc_close_paren = c_parser_peek_token (parser)->location; set_c_expr_source_range (&expr, loc_open_paren, loc_close_paren); @@ -10792,7 +10721,8 @@ c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p, if (locations) locations->safe_push (expr.get_location ()); if (sizeof_arg != NULL - && expr.original_code == SIZEOF_EXPR) + && (expr.original_code == SIZEOF_EXPR + || expr.original_code == PAREN_SIZEOF_EXPR)) { sizeof_arg[0] = c_last_sizeof_arg; sizeof_arg_loc[0] = c_last_sizeof_loc; @@ -10815,7 +10745,8 @@ c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p, locations->safe_push (expr.get_location ()); if (++idx < 3 && sizeof_arg != NULL - && expr.original_code == SIZEOF_EXPR) + && (expr.original_code == SIZEOF_EXPR + || expr.original_code == PAREN_SIZEOF_EXPR)) { sizeof_arg[idx] = c_last_sizeof_arg; sizeof_arg_loc[idx] = c_last_sizeof_loc; @@ -11996,158 +11927,196 @@ c_parser_objc_diagnose_bad_element_prefix (c_parser *parser, static void c_parser_objc_at_property_declaration (c_parser *parser) { - /* The following variables hold the attributes of the properties as - parsed. They are 'false' or 'NULL_TREE' if the attribute was not - seen. When we see an attribute, we set them to 'true' (if they - are boolean properties) or to the identifier (if they have an - argument, ie, for getter and setter). Note that here we only - parse the list of attributes, check the syntax and accumulate the - attributes that we find. objc_add_property_declaration() will - then process the information. */ - bool property_assign = false; - bool property_copy = false; - tree property_getter_ident = NULL_TREE; - bool property_nonatomic = false; - bool property_readonly = false; - bool property_readwrite = false; - bool property_retain = false; - tree property_setter_ident = NULL_TREE; - - /* 'properties' is the list of properties that we read. Usually a - single one, but maybe more (eg, in "@property int a, b, c;" there - are three). */ - tree properties; - location_t loc; - - loc = c_parser_peek_token (parser)->location; gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY)); - + location_t loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); /* Eat '@property'. */ - /* Parse the optional attribute list... */ + /* Parse the optional attribute list. + + A list of parsed, but not verified, attributes. */ + vec<property_attribute_info *> prop_attr_list = vNULL; + + bool syntax_error = false; if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) { matching_parens parens; + location_t attr_start = c_parser_peek_token (parser)->location; /* Eat the '(' */ parens.consume_open (parser); /* Property attribute keywords are valid now. */ parser->objc_property_attr_context = true; - while (true) + /* Allow @property (), with a warning. */ + location_t attr_end = c_parser_peek_token (parser)->location; + + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) { - bool syntax_error = false; - c_token *token = c_parser_peek_token (parser); - enum rid keyword; + location_t attr_comb = make_location (attr_end, attr_start, attr_end); + warning_at (attr_comb, OPT_Wattributes, + "empty property attribute list"); + } + else + while (true) + { + c_token *token = c_parser_peek_token (parser); + attr_start = token->location; + attr_end = get_finish (token->location); + location_t attr_comb = make_location (attr_start, attr_start, + attr_end); - if (token->type != CPP_KEYWORD) - { - if (token->type == CPP_CLOSE_PAREN) - c_parser_error (parser, "expected identifier"); - else - { - c_parser_consume_token (parser); - c_parser_error (parser, "unknown property attribute"); - } - break; - } - keyword = token->keyword; - c_parser_consume_token (parser); - switch (keyword) - { - case RID_ASSIGN: property_assign = true; break; - case RID_COPY: property_copy = true; break; - case RID_NONATOMIC: property_nonatomic = true; break; - case RID_READONLY: property_readonly = true; break; - case RID_READWRITE: property_readwrite = true; break; - case RID_RETAIN: property_retain = true; break; - - case RID_GETTER: - case RID_SETTER: - if (c_parser_next_token_is_not (parser, CPP_EQ)) - { - if (keyword == RID_GETTER) - c_parser_error (parser, - "missing %<=%> (after %<getter%> attribute)"); - else - c_parser_error (parser, - "missing %<=%> (after %<setter%> attribute)"); - syntax_error = true; - break; - } - c_parser_consume_token (parser); /* eat the = */ - if (c_parser_next_token_is_not (parser, CPP_NAME)) - { - c_parser_error (parser, "expected identifier"); - syntax_error = true; + if (token->type == CPP_CLOSE_PAREN || token->type == CPP_COMMA) + { + warning_at (attr_comb, OPT_Wattributes, + "missing property attribute"); + if (token->type == CPP_CLOSE_PAREN) break; - } - if (keyword == RID_SETTER) - { - if (property_setter_ident != NULL_TREE) - c_parser_error (parser, "the %<setter%> attribute may only be specified once"); - else - property_setter_ident = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - if (c_parser_next_token_is_not (parser, CPP_COLON)) - c_parser_error (parser, "setter name must terminate with %<:%>"); - else - c_parser_consume_token (parser); - } - else - { - if (property_getter_ident != NULL_TREE) - c_parser_error (parser, "the %<getter%> attribute may only be specified once"); - else - property_getter_ident = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - } - break; - default: - c_parser_error (parser, "unknown property attribute"); - syntax_error = true; - break; + c_parser_consume_token (parser); + continue; + } + + tree attr_name = NULL_TREE; + enum rid keyword = RID_MAX; /* Not a valid property attribute. */ + bool add_at = false; + if (token->type == CPP_KEYWORD) + { + keyword = token->keyword; + if (OBJC_IS_AT_KEYWORD (keyword)) + { + /* For '@' keywords the token value has the keyword, + prepend the '@' for diagnostics. */ + attr_name = token->value; + add_at = true; + } + else + attr_name = ridpointers[(int)keyword]; + } + else if (token->type == CPP_NAME) + attr_name = token->value; + c_parser_consume_token (parser); + + enum objc_property_attribute_kind prop_kind + = objc_prop_attr_kind_for_rid (keyword); + property_attribute_info *prop + = new property_attribute_info (attr_name, attr_comb, prop_kind); + prop_attr_list.safe_push (prop); + + tree meth_name; + switch (prop->prop_kind) + { + default: break; + case OBJC_PROPERTY_ATTR_UNKNOWN: + if (attr_name) + error_at (attr_comb, "unknown property attribute %<%s%s%>", + add_at ? "@" : "", IDENTIFIER_POINTER (attr_name)); + else + error_at (attr_comb, "unknown property attribute"); + prop->parse_error = syntax_error = true; + break; + + case OBJC_PROPERTY_ATTR_GETTER: + case OBJC_PROPERTY_ATTR_SETTER: + if (c_parser_next_token_is_not (parser, CPP_EQ)) + { + attr_comb = make_location (attr_end, attr_start, attr_end); + error_at (attr_comb, "expected %<=%> after Objective-C %qE", + attr_name); + prop->parse_error = syntax_error = true; + break; + } + token = c_parser_peek_token (parser); + attr_end = token->location; + c_parser_consume_token (parser); /* eat the = */ + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + attr_comb = make_location (attr_end, attr_start, attr_end); + error_at (attr_comb, "expected %qE selector name", + attr_name); + prop->parse_error = syntax_error = true; + break; + } + /* Get the end of the method name, and consume the name. */ + token = c_parser_peek_token (parser); + attr_end = get_finish (token->location); + meth_name = token->value; + c_parser_consume_token (parser); + if (prop->prop_kind == OBJC_PROPERTY_ATTR_SETTER) + { + if (c_parser_next_token_is_not (parser, CPP_COLON)) + { + attr_comb = make_location (attr_end, attr_start, + attr_end); + error_at (attr_comb, "setter method names must" + " terminate with %<:%>"); + prop->parse_error = syntax_error = true; + } + else + { + attr_end = get_finish (c_parser_peek_token + (parser)->location); + c_parser_consume_token (parser); + } + attr_comb = make_location (attr_start, attr_start, + attr_end); + } + else + attr_comb = make_location (attr_start, attr_start, + attr_end); + prop->ident = meth_name; + /* Updated location including all that was successfully + parsed. */ + prop->prop_loc = attr_comb; + break; } - if (syntax_error) - break; - + /* If we see a comma here, then keep going - even if we already + saw a syntax error. For simple mistakes e.g. (asign, getter=x) + this makes a more useful output and avoid spurious warnings about + missing attributes that are, in fact, specified after the one with + the syntax error. */ if (c_parser_next_token_is (parser, CPP_COMMA)) c_parser_consume_token (parser); else break; } parser->objc_property_attr_context = false; - parens.skip_until_found_close (parser); - } - /* ... and the property declaration(s). */ - properties = c_parser_struct_declaration (parser); - if (properties == error_mark_node) - { - c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); - parser->error = false; - return; + if (syntax_error && c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)) + /* We don't really want to chew the whole of the file looking for a + matching closing parenthesis, so we will try to read the decl and + let the error handling for that close out the statement. */ + ; + else + syntax_error = false, parens.skip_until_found_close (parser); } - if (properties == NULL_TREE) - c_parser_error (parser, "expected identifier"); + /* 'properties' is the list of properties that we read. Usually a + single one, but maybe more (eg, in "@property int a, b, c;" there + are three). */ + tree properties = c_parser_struct_declaration (parser); + + if (properties == error_mark_node) + c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); else { - /* Comma-separated properties are chained together in - reverse order; add them one by one. */ - properties = nreverse (properties); - - for (; properties; properties = TREE_CHAIN (properties)) - objc_add_property_declaration (loc, copy_node (properties), - property_readonly, property_readwrite, - property_assign, property_retain, - property_copy, property_nonatomic, - property_getter_ident, property_setter_ident); + if (properties == NULL_TREE) + c_parser_error (parser, "expected identifier"); + else + { + /* Comma-separated properties are chained together in reverse order; + add them one by one. */ + properties = nreverse (properties); + for (; properties; properties = TREE_CHAIN (properties)) + objc_add_property_declaration (loc, copy_node (properties), + prop_attr_list); + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); } - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + while (!prop_attr_list.is_empty()) + delete prop_attr_list.pop (); + prop_attr_list.release (); parser->error = false; } @@ -12641,6 +12610,8 @@ c_parser_omp_clause_name (c_parser *parser) case 'a': if (!strcmp ("aligned", p)) result = PRAGMA_OMP_CLAUSE_ALIGNED; + else if (!strcmp ("allocate", p)) + result = PRAGMA_OMP_CLAUSE_ALLOCATE; else if (!strcmp ("async", p)) result = PRAGMA_OACC_CLAUSE_ASYNC; else if (!strcmp ("attach", p)) @@ -15150,6 +15121,62 @@ c_parser_omp_clause_aligned (c_parser *parser, tree list) return nl; } +/* OpenMP 5.0: + allocate ( variable-list ) + allocate ( expression : variable-list ) */ + +static tree +c_parser_omp_clause_allocate (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + tree nl, c; + tree allocator = NULL_TREE; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + if ((c_parser_next_token_is_not (parser, CPP_NAME) + && c_parser_next_token_is_not (parser, CPP_KEYWORD)) + || (c_parser_peek_2nd_token (parser)->type != CPP_COMMA + && c_parser_peek_2nd_token (parser)->type != CPP_CLOSE_PAREN)) + { + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); + allocator = expr.value; + allocator = c_fully_fold (allocator, false, NULL); + tree orig_type + = expr.original_type ? expr.original_type : TREE_TYPE (allocator); + orig_type = TYPE_MAIN_VARIANT (orig_type); + if (!INTEGRAL_TYPE_P (TREE_TYPE (allocator)) + || TREE_CODE (orig_type) != ENUMERAL_TYPE + || TYPE_NAME (orig_type) != get_identifier ("omp_allocator_handle_t")) + { + error_at (clause_loc, "%<allocate%> clause allocator expression " + "has type %qT rather than " + "%<omp_allocator_handle_t%>", + TREE_TYPE (allocator)); + allocator = NULL_TREE; + } + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + { + parens.skip_until_found_close (parser); + return list; + } + } + + nl = c_parser_omp_variable_list (parser, clause_loc, + OMP_CLAUSE_ALLOCATE, list); + + if (allocator) + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) = allocator; + + parens.skip_until_found_close (parser); + return nl; +} + /* OpenMP 4.0: linear ( variable-list ) linear ( variable-list : expression ) @@ -16392,6 +16419,10 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, clauses = c_parser_omp_clause_aligned (parser, clauses); c_name = "aligned"; break; + case PRAGMA_OMP_CLAUSE_ALLOCATE: + clauses = c_parser_omp_clause_allocate (parser, clauses); + c_name = "allocate"; + break; case PRAGMA_OMP_CLAUSE_LINEAR: clauses = c_parser_omp_clause_linear (parser, clauses); c_name = "linear"; @@ -17280,7 +17311,7 @@ c_parser_oacc_wait (location_t loc, c_parser *parser, char *p_name) LOC is the location of the #pragma token. */ static void -c_parser_omp_atomic (location_t loc, c_parser *parser) +c_parser_omp_atomic (location_t loc, c_parser *parser, bool openacc) { tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE; tree lhs1 = NULL_TREE, rhs1 = NULL_TREE; @@ -17319,6 +17350,12 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) new_code = OMP_ATOMIC; else if (!strcmp (p, "capture")) new_code = OMP_ATOMIC_CAPTURE_NEW; + else if (openacc) + { + p = NULL; + error_at (cloc, "expected %<read%>, %<write%>, %<update%>, " + "or %<capture%> clause"); + } else if (!strcmp (p, "seq_cst")) new_memory_order = OMP_MEMORY_ORDER_SEQ_CST; else if (!strcmp (p, "acq_rel")) @@ -17346,7 +17383,12 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) { if (new_code != ERROR_MARK) { - if (code != ERROR_MARK) + /* OpenACC permits 'update capture'. */ + if (openacc + && code == OMP_ATOMIC + && new_code == OMP_ATOMIC_CAPTURE_NEW) + code = new_code; + else if (code != ERROR_MARK) error_at (cloc, "too many atomic clauses"); else code = new_code; @@ -17368,7 +17410,9 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) if (code == ERROR_MARK) code = OMP_ATOMIC; - if (memory_order == OMP_MEMORY_ORDER_UNSPECIFIED) + if (openacc) + memory_order = OMP_MEMORY_ORDER_RELAXED; + else if (memory_order == OMP_MEMORY_ORDER_UNSPECIFIED) { omp_requires_mask = (enum omp_requires) (omp_requires_mask @@ -17424,6 +17468,7 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) } break; case OMP_ATOMIC: + /* case OMP_ATOMIC_CAPTURE_NEW: - or update to OpenMP 5.1 */ if (memory_order == OMP_MEMORY_ORDER_ACQ_REL || memory_order == OMP_MEMORY_ORDER_ACQUIRE) { @@ -18572,6 +18617,7 @@ c_parser_omp_simd (location_t loc, c_parser *parser, | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER)) static tree @@ -18863,6 +18909,7 @@ c_parser_omp_sections_scope (location_t sections_loc, c_parser *parser) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree @@ -18917,6 +18964,7 @@ c_parser_omp_sections (location_t loc, c_parser *parser, | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYIN) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PROC_BIND)) static tree @@ -19058,6 +19106,7 @@ c_parser_omp_parallel (location_t loc, c_parser *parser, ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree @@ -19092,6 +19141,7 @@ c_parser_omp_single (location_t loc, c_parser *parser, bool *if_p) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION)) static tree @@ -19162,7 +19212,8 @@ c_parser_omp_taskyield (c_parser *parser) */ #define OMP_TASKGROUP_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASK_REDUCTION)) + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASK_REDUCTION)) static tree c_parser_omp_taskgroup (location_t loc, c_parser *parser, bool *if_p) @@ -19263,6 +19314,7 @@ c_parser_omp_cancellation_point (c_parser *parser, enum pragma_context context) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)\ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE)) static tree @@ -19352,6 +19404,7 @@ c_parser_omp_distribute (location_t loc, c_parser *parser, | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT)) static tree @@ -19458,6 +19511,7 @@ c_parser_omp_target_data (location_t loc, c_parser *parser, bool *if_p) tree clauses = c_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK, "#pragma omp target data"); + c_omp_adjust_map_clauses (clauses, false); int map_seen = 0; for (tree *pc = &clauses; *pc;) { @@ -19475,6 +19529,7 @@ c_parser_omp_target_data (location_t loc, c_parser *parser, bool *if_p) break; case GOMP_MAP_FIRSTPRIVATE_POINTER: case GOMP_MAP_ALWAYS_POINTER: + case GOMP_MAP_ATTACH_DETACH: break; default: map_seen |= 1; @@ -19598,6 +19653,7 @@ c_parser_omp_target_enter_data (location_t loc, c_parser *parser, tree clauses = c_parser_omp_all_clauses (parser, OMP_TARGET_ENTER_DATA_CLAUSE_MASK, "#pragma omp target enter data"); + c_omp_adjust_map_clauses (clauses, false); int map_seen = 0; for (tree *pc = &clauses; *pc;) { @@ -19611,6 +19667,7 @@ c_parser_omp_target_enter_data (location_t loc, c_parser *parser, break; case GOMP_MAP_FIRSTPRIVATE_POINTER: case GOMP_MAP_ALWAYS_POINTER: + case GOMP_MAP_ATTACH_DETACH: break; default: map_seen |= 1; @@ -19682,7 +19739,7 @@ c_parser_omp_target_exit_data (location_t loc, c_parser *parser, tree clauses = c_parser_omp_all_clauses (parser, OMP_TARGET_EXIT_DATA_CLAUSE_MASK, "#pragma omp target exit data"); - + c_omp_adjust_map_clauses (clauses, false); int map_seen = 0; for (tree *pc = &clauses; *pc;) { @@ -19697,6 +19754,7 @@ c_parser_omp_target_exit_data (location_t loc, c_parser *parser, break; case GOMP_MAP_FIRSTPRIVATE_POINTER: case GOMP_MAP_ALWAYS_POINTER: + case GOMP_MAP_ATTACH_DETACH: break; default: map_seen |= 1; @@ -19739,6 +19797,7 @@ c_parser_omp_target_exit_data (location_t loc, c_parser *parser, | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULTMAP) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR)) @@ -19906,6 +19965,8 @@ c_parser_omp_target (c_parser *parser, enum pragma_context context, bool *if_p) OMP_TARGET_CLAUSES (stmt) = c_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK, "#pragma omp target"); + c_omp_adjust_map_clauses (OMP_TARGET_CLAUSES (stmt), true); + pc = &OMP_TARGET_CLAUSES (stmt); keep_next_level (); block = c_begin_compound_stmt (true); @@ -19930,6 +19991,7 @@ check_clauses: case GOMP_MAP_ALLOC: case GOMP_MAP_FIRSTPRIVATE_POINTER: case GOMP_MAP_ALWAYS_POINTER: + case GOMP_MAP_ATTACH_DETACH: break; default: error_at (OMP_CLAUSE_LOCATION (*pc), @@ -21369,6 +21431,7 @@ c_finish_taskloop_clauses (tree clauses) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOGROUP) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION)) @@ -21455,7 +21518,7 @@ c_parser_omp_construct (c_parser *parser, bool *if_p) switch (p_kind) { case PRAGMA_OACC_ATOMIC: - c_parser_omp_atomic (loc, parser); + c_parser_omp_atomic (loc, parser, true); return; case PRAGMA_OACC_CACHE: strcpy (p_name, "#pragma acc"); @@ -21482,7 +21545,7 @@ c_parser_omp_construct (c_parser *parser, bool *if_p) stmt = c_parser_oacc_wait (loc, parser, p_name); break; case PRAGMA_OMP_ATOMIC: - c_parser_omp_atomic (loc, parser); + c_parser_omp_atomic (loc, parser, false); return; case PRAGMA_OMP_CRITICAL: stmt = c_parser_omp_critical (loc, parser, if_p); diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 287b1df..1f783db 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -675,6 +675,7 @@ extern location_t c_last_sizeof_loc; extern struct c_switch *c_switch_stack; +extern bool char_type_p (tree); extern tree c_objc_common_truthvalue_conversion (location_t, tree); extern tree require_complete_type (location_t, tree); extern bool same_translation_unit_p (const_tree, const_tree); diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index dd3e309..df1dad4 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -1407,7 +1407,7 @@ free_all_tagged_tu_seen_up_to (const struct tagged_tu_seen_cache *tu_til) const struct tagged_tu_seen_cache *const tu1 = (const struct tagged_tu_seen_cache *) tu; tu = tu1->next; - free (CONST_CAST (struct tagged_tu_seen_cache *, tu1)); + XDELETE (CONST_CAST (struct tagged_tu_seen_cache *, tu1)); } tagged_tu_seen_base = tu_til; } @@ -3014,7 +3014,8 @@ build_function_call (location_t loc, tree function, tree params) static void inform_declaration (tree decl) { - if (decl && (TREE_CODE (decl) != FUNCTION_DECL || !DECL_IS_BUILTIN (decl))) + if (decl && (TREE_CODE (decl) != FUNCTION_DECL + || !DECL_IS_UNDECLARED_BUILTIN (decl))) inform (DECL_SOURCE_LOCATION (decl), "declared here"); } @@ -3719,7 +3720,7 @@ parser_build_unary_op (location_t loc, enum tree_code code, struct c_expr arg) /* Returns true if TYPE is a character type, *not* including wchar_t. */ -static bool +bool char_type_p (tree type) { return (type == char_type_node @@ -5490,6 +5491,82 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, return ret; } +/* EXPR is an expression, location LOC, whose result is discarded. + Warn if it is a call to a nodiscard function (or a COMPOUND_EXPR + whose right-hand operand is such a call, possibly recursively). */ + +static void +maybe_warn_nodiscard (location_t loc, tree expr) +{ + if (VOID_TYPE_P (TREE_TYPE (expr))) + return; + while (TREE_CODE (expr) == COMPOUND_EXPR) + { + expr = TREE_OPERAND (expr, 1); + if (EXPR_HAS_LOCATION (expr)) + loc = EXPR_LOCATION (expr); + } + if (TREE_CODE (expr) != CALL_EXPR) + return; + tree fn = CALL_EXPR_FN (expr); + if (!fn) + return; + tree attr; + if (TREE_CODE (fn) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL + && (attr = lookup_attribute ("nodiscard", + DECL_ATTRIBUTES (TREE_OPERAND (fn, 0))))) + { + fn = TREE_OPERAND (fn, 0); + tree args = TREE_VALUE (attr); + if (args) + args = TREE_VALUE (args); + auto_diagnostic_group d; + int warned; + if (args) + warned = warning_at (loc, OPT_Wunused_result, + "ignoring return value of %qD, declared with " + "attribute %<nodiscard%>: %E", fn, args); + else + warned = warning_at (loc, OPT_Wunused_result, + "ignoring return value of %qD, declared with " + "attribute %<nodiscard%>", fn); + if (warned) + inform (DECL_SOURCE_LOCATION (fn), "declared here"); + } + else + { + tree rettype = TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))); + attr = lookup_attribute ("nodiscard", TYPE_ATTRIBUTES (rettype)); + if (!attr) + return; + tree args = TREE_VALUE (attr); + if (args) + args = TREE_VALUE (args); + auto_diagnostic_group d; + int warned; + if (args) + warned = warning_at (loc, OPT_Wunused_result, + "ignoring return value of type %qT, declared " + "with attribute %<nodiscard%>: %E", + rettype, args); + else + warned = warning_at (loc, OPT_Wunused_result, + "ignoring return value of type %qT, declared " + "with attribute %<nodiscard%>", rettype); + if (warned) + { + if (TREE_CODE (fn) == ADDR_EXPR) + { + fn = TREE_OPERAND (fn, 0); + if (TREE_CODE (fn) == FUNCTION_DECL) + inform (DECL_SOURCE_LOCATION (fn), + "in call to %qD, declared here", fn); + } + } + } +} + /* Return a compound expression that performs two expressions and returns the value of the second of them. @@ -5561,6 +5638,8 @@ build_compound_expr (location_t loc, tree expr1, tree expr2) else if (warn_unused_value) warn_if_unused_value (expr1, loc); + maybe_warn_nodiscard (loc, expr1); + if (expr2 == error_mark_node) return error_mark_node; @@ -6500,7 +6579,7 @@ inform_for_arg (tree fundecl, location_t ploc, int parmnum, tree expected_type, tree actual_type) { location_t loc; - if (fundecl && !DECL_IS_BUILTIN (fundecl)) + if (fundecl && !DECL_IS_UNDECLARED_BUILTIN (fundecl)) loc = get_fndecl_argument_location (fundecl, parmnum - 1); else loc = ploc; @@ -6750,7 +6829,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, if (pedwarn (expr_loc, OPT_Wc___compat, "enum conversion when " "passing argument %d of %qE is invalid in C++", parmnum, rname)) - inform ((fundecl && !DECL_IS_BUILTIN (fundecl)) + inform ((fundecl && !DECL_IS_UNDECLARED_BUILTIN (fundecl)) ? DECL_SOURCE_LOCATION (fundecl) : expr_loc, "expected %qT but argument is of type %qT", type, rhstype); @@ -7161,7 +7240,8 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, case ic_argpass: /* Do not warn for built-in functions, for example memcpy, since we control how they behave and they can be useful in this area. */ - if (TREE_CODE (rname) != FUNCTION_DECL || !DECL_IS_BUILTIN (rname)) + if (TREE_CODE (rname) != FUNCTION_DECL + || !DECL_IS_UNDECLARED_BUILTIN (rname)) warning_at (location, OPT_Wscalar_storage_order, "passing argument %d of %qE from incompatible " "scalar storage order", parmnum, rname); @@ -8314,13 +8394,13 @@ finish_init (void) { struct constructor_stack *q = constructor_stack; constructor_stack = q->next; - free (q); + XDELETE (q); } gcc_assert (!constructor_range_stack); /* Pop back to the data of the outer initializer (if any). */ - free (spelling_base); + XDELETE (spelling_base); constructor_decl = p->decl; require_constant_value = p->require_constant_value; @@ -8333,7 +8413,7 @@ finish_init (void) spelling_size = p->spelling_size; constructor_top_level = p->top_level; initializer_stack = p->next; - free (p); + XDELETE (p); } /* Call here when we see the initializer is surrounded by braces. @@ -8864,7 +8944,7 @@ pop_init_level (location_t loc, int implicit, RESTORE_SPELLING_DEPTH (constructor_depth); constructor_stack = p->next; - free (p); + XDELETE (p); if (ret.value == NULL_TREE && constructor_stack == 0) ret.value = error_mark_node; @@ -11072,6 +11152,9 @@ c_finish_bc_stmt (location_t loc, tree label, bool is_break) static void emit_side_effect_warnings (location_t loc, tree expr) { + maybe_warn_nodiscard (loc, expr); + if (!warn_unused_value) + return; if (expr == error_mark_node) ; else if (!TREE_SIDE_EFFECTS (expr)) @@ -11127,7 +11210,7 @@ c_process_expr_stmt (location_t loc, tree expr) Warnings for statement expressions will be emitted later, once we figure out which is the result. */ if (!STATEMENT_LIST_STMT_EXPR (cur_stmt_list) - && warn_unused_value) + && (warn_unused_value || warn_unused_result)) emit_side_effect_warnings (EXPR_LOC_OR_LOC (expr, loc), expr); exprv = expr; @@ -11221,7 +11304,7 @@ c_finish_stmt_expr (location_t loc, tree body) /* If we're supposed to generate side effects warnings, process all of the statements except the last. */ - if (warn_unused_value) + if (warn_unused_value || warn_unused_result) { for (tree_stmt_iterator i = tsi_start (last); tsi_stmt (i) != tsi_stmt (l); tsi_next (&i)) @@ -13501,11 +13584,7 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) if (ort != C_ORT_OMP && ort != C_ORT_ACC) OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_POINTER); else if (TREE_CODE (t) == COMPONENT_REF) - { - gomp_map_kind k = (ort == C_ORT_ACC) ? GOMP_MAP_ATTACH_DETACH - : GOMP_MAP_ALWAYS_POINTER; - OMP_CLAUSE_SET_MAP_KIND (c2, k); - } + OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ATTACH_DETACH); else OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_FIRSTPRIVATE_POINTER); if (OMP_CLAUSE_MAP_KIND (c2) != GOMP_MAP_FIRSTPRIVATE_POINTER @@ -13795,6 +13874,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) /* 1 if normal/task reduction has been seen, -1 if inscan reduction has been seen, -2 if mixed inscan/normal reduction diagnosed. */ int reduction_seen = 0; + bool allocate_seen = false; bitmap_obstack_initialize (NULL); bitmap_initialize (&generic_head, &bitmap_default_obstack); @@ -14344,6 +14424,29 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) bitmap_set_bit (&oacc_reduction_head, DECL_UID (t)); break; + case OMP_CLAUSE_ALLOCATE: + t = OMP_CLAUSE_DECL (c); + if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in %<allocate%> clause", t); + remove = true; + } + else if (bitmap_bit_p (&aligned_head, DECL_UID (t))) + { + warning_at (OMP_CLAUSE_LOCATION (c), 0, + "%qE appears more than once in %<allocate%> clauses", + t); + remove = true; + } + else + { + bitmap_set_bit (&aligned_head, DECL_UID (t)); + if (!OMP_CLAUSE_ALLOCATE_COMBINED (c)) + allocate_seen = true; + } + break; + case OMP_CLAUSE_DEPEND: t = OMP_CLAUSE_DECL (c); if (t == NULL_TREE) @@ -14604,7 +14707,9 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) break; if (VAR_P (t) || TREE_CODE (t) == PARM_DECL) { - if (bitmap_bit_p (&map_field_head, DECL_UID (t))) + if (bitmap_bit_p (&map_field_head, DECL_UID (t)) + || (ort == C_ORT_OMP + && bitmap_bit_p (&map_head, DECL_UID (t)))) break; } } @@ -14673,7 +14778,9 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) else bitmap_set_bit (&generic_head, DECL_UID (t)); } - else if (bitmap_bit_p (&map_head, DECL_UID (t))) + else if (bitmap_bit_p (&map_head, DECL_UID (t)) + && (ort != C_ORT_OMP + || !bitmap_bit_p (&map_field_head, DECL_UID (t)))) { if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) error_at (OMP_CLAUSE_LOCATION (c), @@ -14687,7 +14794,13 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) remove = true; } else if (bitmap_bit_p (&generic_head, DECL_UID (t)) - || bitmap_bit_p (&firstprivate_head, DECL_UID (t))) + && ort == C_ORT_ACC) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in data clauses", t); + remove = true; + } + else if (bitmap_bit_p (&firstprivate_head, DECL_UID (t))) { if (ort == C_ORT_ACC) error_at (OMP_CLAUSE_LOCATION (c), @@ -15041,10 +15154,40 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) reduction_seen = -2; } - if (linear_variable_step_check || reduction_seen == -2) + if (linear_variable_step_check || reduction_seen == -2 || allocate_seen) for (pc = &clauses, c = clauses; c ; c = *pc) { bool remove = false; + if (allocate_seen) + switch (OMP_CLAUSE_CODE (c)) + { + case OMP_CLAUSE_REDUCTION: + case OMP_CLAUSE_IN_REDUCTION: + case OMP_CLAUSE_TASK_REDUCTION: + if (TREE_CODE (OMP_CLAUSE_DECL (c)) == MEM_REF) + { + t = TREE_OPERAND (OMP_CLAUSE_DECL (c), 0); + if (TREE_CODE (t) == POINTER_PLUS_EXPR) + t = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == ADDR_EXPR + || TREE_CODE (t) == INDIRECT_REF) + t = TREE_OPERAND (t, 0); + if (DECL_P (t)) + bitmap_clear_bit (&aligned_head, DECL_UID (t)); + break; + } + /* FALLTHRU */ + case OMP_CLAUSE_PRIVATE: + case OMP_CLAUSE_FIRSTPRIVATE: + case OMP_CLAUSE_LASTPRIVATE: + case OMP_CLAUSE_LINEAR: + if (DECL_P (OMP_CLAUSE_DECL (c))) + bitmap_clear_bit (&aligned_head, + DECL_UID (OMP_CLAUSE_DECL (c))); + break; + default: + break; + } if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR && OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c) && !bitmap_bit_p (&map_head, @@ -15065,6 +15208,25 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) pc = &OMP_CLAUSE_CHAIN (c); } + if (allocate_seen) + for (pc = &clauses, c = clauses; c ; c = *pc) + { + bool remove = false; + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_ALLOCATE + && !OMP_CLAUSE_ALLOCATE_COMBINED (c) + && bitmap_bit_p (&aligned_head, DECL_UID (OMP_CLAUSE_DECL (c)))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD specified in %<allocate%> clause but not in " + "an explicit privatization clause", OMP_CLAUSE_DECL (c)); + remove = true; + } + if (remove) + *pc = OMP_CLAUSE_CHAIN (c); + else + pc = &OMP_CLAUSE_CHAIN (c); + } + if (nogroup_seen && reduction_seen) { error_at (OMP_CLAUSE_LOCATION (*nogroup_seen), |