diff options
author | Martin Liska <mliska@suse.cz> | 2022-11-07 08:24:48 +0100 |
---|---|---|
committer | Martin Liska <mliska@suse.cz> | 2022-11-07 08:24:48 +0100 |
commit | 1b09b78ee61bd921ae78ebd0f7905b95b9e1c903 (patch) | |
tree | 9c04b59cdd2cd460f0727501d15402d31ffcf5a4 /gcc/c | |
parent | 1eb021edb27e26f95cda63df121f6bc951647599 (diff) | |
parent | c4f8f8afd07680f9e718de1331cd09607bdd9ac8 (diff) | |
download | gcc-1b09b78ee61bd921ae78ebd0f7905b95b9e1c903.zip gcc-1b09b78ee61bd921ae78ebd0f7905b95b9e1c903.tar.gz gcc-1b09b78ee61bd921ae78ebd0f7905b95b9e1c903.tar.bz2 |
Merge branch 'master' into devel/sphinx
Diffstat (limited to 'gcc/c')
-rw-r--r-- | gcc/c/ChangeLog | 103 | ||||
-rw-r--r-- | gcc/c/c-decl.cc | 156 | ||||
-rw-r--r-- | gcc/c/c-parser.cc | 167 | ||||
-rw-r--r-- | gcc/c/c-tree.h | 13 | ||||
-rw-r--r-- | gcc/c/c-typeck.cc | 23 |
5 files changed, 391 insertions, 71 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 2ac8eaa..95053e8 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,106 @@ +2022-11-03 Joseph Myers <joseph@codesourcery.com> + + * c-decl.cc (in_underspecified_init, start_underspecified_init) + (finish_underspecified_init): New. + (shadow_tag_warned, parser_xref_tag, start_struct, start_enum): + Give errors inside initializers of underspecified declarations. + (grokdeclarator): Handle (erroneous) case of C2X auto on a + parameter. + (declspecs_add_type): Handle c2x_auto_p case. + (declspecs_add_scspec): Handle auto possibly setting c2x_auto_p in + C2X mode. + (finish_declspecs): Handle c2x_auto_p. + * c-parser.cc (c_parser_declaration_or_fndef): Handle C2X auto. + * c-tree.h (C_DECL_UNDERSPECIFIED): New macro. + (struct c_declspecs): Add c2x_auto_p. + (start_underspecified_init, finish_underspecified_init): New + prototypes. + * c-typeck.cc (build_external_ref): Give error for underspecified + declaration referenced in its initializer. + +2022-10-28 Joseph Myers <joseph@codesourcery.com> + + * c-decl.cc (grokdeclarator): Pass + arg_info->no_named_args_stdarg_p to build_function_type. + (grokparms): Check arg_info->no_named_args_stdarg_p before + converting () to (void). + (build_arg_info): Initialize no_named_args_stdarg_p. + (get_parm_info): Set no_named_args_stdarg_p. + (start_function): Pass TYPE_NO_NAMED_ARGS_STDARG_P to + build_function_type. + (store_parm_decls): Count (...) functions as prototyped. + * c-parser.cc (c_parser_direct_declarator): Allow '...' after open + parenthesis to start parameter list. + (c_parser_parms_list_declarator): Always allow '...' with no + arguments, call pedwarn_c11 and set no_named_args_stdarg_p. + * c-tree.h (struct c_arg_info): Add field no_named_args_stdarg_p. + * c-typeck.cc (composite_type): Handle + TYPE_NO_NAMED_ARGS_STDARG_P. + (function_types_compatible_p): Compare + TYPE_NO_NAMED_ARGS_STDARG_P. + +2022-10-28 Jakub Jelinek <jakub@redhat.com> + + * c-parser.cc (c_parser_omp_all_clauses): Allow optional + comma before the first clause. + (c_parser_omp_allocate, c_parser_omp_atomic, c_parser_omp_depobj, + c_parser_omp_flush, c_parser_omp_scan_loop_body, + c_parser_omp_ordered, c_finish_omp_declare_variant, + c_parser_omp_declare_target, c_parser_omp_declare_reduction, + c_parser_omp_requires, c_parser_omp_error, + c_parser_omp_assumption_clauses): Likewise. + +2022-10-28 Joseph Myers <joseph@codesourcery.com> + + PR c/61469 + * c-convert.cc (c_convert): Handle enums with underlying boolean + type like bool. + * c-decl.cc (shadow_tag_warned): Allow shadowing declarations for + enums with enum type specifier, but give errors for storage class + specifiers, qualifiers or alignment specifiers in non-definition + declarations of such enums. + (grokdeclarator): Give error for non-definition use of type + specifier with an enum type specifier. + (parser_xref_tag): Add argument has_enum_type_specifier. Pass it + to lookup_tag and use it to set ENUM_FIXED_UNDERLYING_TYPE_P. + (xref_tag): Update call to parser_xref_tag. + (start_enum): Add argument fixed_underlying_type. Complete enum + type with a fixed underlying type given in the definition. Give + error for defining without a fixed underlying type in the + definition if one was given in a prior declaration. Do not mark + enums with fixed underlying type as packed for -fshort-enums. + Store the enum type in the_enum. + (finish_enum): Do not adjust types of values or check their range + for an enum with a fixed underlying type. Set underlying type of + enum and variants. + (build_enumerator): Check enumeration constants for enum with + fixed underlying type against that type and convert to that type. + Increment in the underlying integer type, with handling for bool. + (c_simulate_enum_decl): Update call to start_enum. + (declspecs_add_type): Set specs->enum_type_specifier_ref_p. + * c-objc-common.cc (c_get_alias_set): Use ENUM_UNDERLYING_TYPE + rather than recomputing an underlying type based on size. + * c-parser.cc (c_parser_declspecs) + (c_parser_struct_or_union_specifier, c_parser_typeof_specifier): + Set has_enum_type_specifier for type specifiers. + (c_parser_enum_specifier): Handle enum type specifiers. + (c_parser_struct_or_union_specifier): Update call to + parser_xref_tag. + (c_parser_omp_atomic): Check for boolean increment or decrement + using C_BOOLEAN_TYPE_P. + * c-tree.h (C_BOOLEAN_TYPE_P): New. + (struct c_typespec): Add has_enum_type_specifier. + (struct c_declspecs): Add enum_type_specifier_ref_p. + (struct c_enum_contents): Add enum_type. + (start_enum, parser_xref_tag): Update prototypes. + * c-typeck.cc (composite_type): Allow for enumerated types + compatible with bool. + (common_type, comptypes_internal, perform_integral_promotions): + Use ENUM_UNDERLYING_TYPE. + (parser_build_binary_op, build_unary_op, convert_for_assignment) + (c_finish_return, c_start_switch, build_binary_op): Check for + boolean types using C_BOOLEAN_TYPE_P. + 2022-10-24 Jakub Jelinek <jakub@redhat.com> PR c++/107358 diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 2b83900..a99b745 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -1472,6 +1472,67 @@ pop_file_scope (void) maybe_apply_pending_pragma_weaks (); } +/* Whether we are curently inside the initializer for an + underspecified object definition (C2x auto or constexpr). */ +static bool in_underspecified_init; + +/* Start an underspecified object definition for NAME at LOC. This + means that NAME is shadowed inside its initializer, so neither the + definition being initialized, nor any definition from an outer + scope, may be referenced during that initializer. Return state to + be passed to finish_underspecified_init. */ +unsigned int +start_underspecified_init (location_t loc, tree name) +{ + bool prev = in_underspecified_init; + bool ok; + tree decl = build_decl (loc, VAR_DECL, name, error_mark_node); + C_DECL_UNDERSPECIFIED (decl) = 1; + struct c_scope *scope = current_scope; + struct c_binding *b = I_SYMBOL_BINDING (name); + if (b && B_IN_SCOPE (b, scope)) + { + error_at (loc, "underspecified declaration of %qE, which is already " + "declared in this scope", name); + ok = false; + } + else + { + bind (name, decl, scope, false, false, loc); + ok = true; + } + in_underspecified_init = true; + return ok | (prev << 1); +} + +/* Finish an underspecified object definition for NAME, before that + name is bound to the real declaration instead of a placeholder. + PREV_STATE is the value returned by the call to + start_underspecified_init. */ +void +finish_underspecified_init (tree name, unsigned int prev_state) +{ + if (prev_state & 1) + { + /* A VAR_DECL was bound to the name to shadow any previous + declarations for the name; remove that binding now. */ + struct c_scope *scope = current_scope; + struct c_binding *b = I_SYMBOL_BINDING (name); + gcc_assert (b); + gcc_assert (B_IN_SCOPE (b, scope)); + gcc_assert (VAR_P (b->decl)); + gcc_assert (C_DECL_UNDERSPECIFIED (b->decl)); + I_SYMBOL_BINDING (name) = b->shadowed; + /* In erroneous cases there may be other bindings added to this + scope during the initializer. */ + struct c_binding **p = &scope->bindings; + while (*p != b) + p = &((*p)->prev); + *p = free_binding_and_advance (*p); + } + in_underspecified_init = (prev_state & (1u << 1)) >> 1; +} + /* Adjust the bindings for the start of a statement expression. */ void @@ -4764,6 +4825,17 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned) warned = 1; } + if (in_underspecified_init) + { + /* This can only occur with extensions such as statement + expressions, but is still appropriate as an error to + avoid types declared in such a context escaping to + the type of an auto variable. */ + error ("%qT declared in underspecified object initializer", + value); + warned = 1; + } + if (name == NULL_TREE) { if (warned != 1 && code != ENUMERAL_TYPE) @@ -6458,6 +6530,15 @@ grokdeclarator (const struct c_declarator *declarator, enum c_declarator_kind first_non_attr_kind; unsigned int alignas_align = 0; + if (type == NULL_TREE) + { + /* This can occur for auto on a parameter in C2X mode. Set a + dummy type here so subsequent code can give diagnostics for + this case. */ + gcc_assert (declspecs->c2x_auto_p); + gcc_assert (decl_context == PARM); + type = declspecs->type = integer_type_node; + } if (TREE_CODE (type) == ERROR_MARK) return error_mark_node; if (expr == NULL) @@ -6683,9 +6764,13 @@ grokdeclarator (const struct c_declarator *declarator, || storage_class == csc_typedef) storage_class = csc_none; } - else if (decl_context != NORMAL && (storage_class != csc_none || threadp)) + else if (decl_context != NORMAL && (storage_class != csc_none + || threadp + || declspecs->c2x_auto_p)) { - if (decl_context == PARM && storage_class == csc_register) + if (decl_context == PARM + && storage_class == csc_register + && !declspecs->c2x_auto_p) ; else { @@ -7295,7 +7380,8 @@ grokdeclarator (const struct c_declarator *declarator, } type_quals = TYPE_UNQUALIFIED; - type = build_function_type (type, arg_types); + type = build_function_type (type, arg_types, + arg_info->no_named_args_stdarg_p); declarator = declarator->declarator; /* Set the TYPE_CONTEXTs for each tagged type which is local to @@ -8060,7 +8146,8 @@ grokparms (struct c_arg_info *arg_info, bool funcdef_flag) /* In C2X, convert () to (void). */ if (flag_isoc2x && !arg_types - && !arg_info->parms) + && !arg_info->parms + && !arg_info->no_named_args_stdarg_p) arg_types = arg_info->types = void_list_node; /* If there is a parameter of incomplete type in a definition, @@ -8130,6 +8217,7 @@ build_arg_info (void) ret->others = NULL_TREE; ret->pending_sizes = NULL; ret->had_vla_unspec = 0; + ret->no_named_args_stdarg_p = 0; return ret; } @@ -8321,6 +8409,7 @@ get_parm_info (bool ellipsis, tree expr) arg_info->types = types; arg_info->others = others; arg_info->pending_sizes = expr; + arg_info->no_named_args_stdarg_p = ellipsis && !types; return arg_info; } @@ -8424,6 +8513,9 @@ parser_xref_tag (location_t loc, enum tree_code code, tree name, pushtag (loc, name, ref); decl_attributes (&ref, attrs, (int) ATTR_FLAG_TYPE_IN_PLACE); + if (in_underspecified_init) + error_at (loc, "%qT declared in underspecified object initializer", + ref); ret.spec = ref; return ret; @@ -8519,6 +8611,9 @@ start_struct (location_t loc, enum tree_code code, tree name, ? "sizeof" : (in_typeof ? "typeof" : "alignof"))); + if (in_underspecified_init) + error_at (loc, "%qT defined in underspecified object initializer", ref); + return ref; } @@ -9429,6 +9524,10 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name, ? "sizeof" : (in_typeof ? "typeof" : "alignof"))); + if (in_underspecified_init) + error_at (loc, "%qT defined in underspecified object initializer", + enumtype); + return enumtype; } @@ -9935,7 +10034,8 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, /* Make it return void instead. */ TREE_TYPE (decl1) = build_function_type (void_type_node, - TYPE_ARG_TYPES (TREE_TYPE (decl1))); + TYPE_ARG_TYPES (TREE_TYPE (decl1)), + TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (decl1))); } if (warn_about_return_type) @@ -10534,7 +10634,7 @@ store_parm_decls (void) empty argument list was converted to (void) in grokparms; in older C standard versions, it does not give the function a type with a prototype for future calls. */ - proto = arg_info->types != 0; + proto = arg_info->types != 0 || arg_info->no_named_args_stdarg_p; if (proto) store_parm_decls_newstyle (fndecl, arg_info); @@ -11256,6 +11356,20 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, if (TREE_UNAVAILABLE (type)) specs->unavailable_p = true; + /* As a type specifier is present, "auto" must be used as a storage + class specifier, not for type deduction. */ + if (specs->c2x_auto_p) + { + specs->c2x_auto_p = false; + if (specs->storage_class != csc_none) + error ("multiple storage classes in declaration specifiers"); + else if (specs->thread_p) + error ("%qs used with %<auto%>", + specs->thread_gnu_p ? "__thread" : "_Thread_local"); + else + specs->storage_class = csc_auto; + } + /* Handle type specifier keywords. */ if (TREE_CODE (type) == IDENTIFIER_NODE && C_IS_RESERVED_WORD (type) @@ -12174,6 +12288,16 @@ declspecs_add_scspec (location_t loc, } break; case RID_AUTO: + if (flag_isoc2x + && specs->typespec_kind == ctsk_none + && specs->storage_class != csc_typedef) + { + /* "auto" potentially used for type deduction. */ + if (specs->c2x_auto_p) + error ("duplicate %qE", scspec); + specs->c2x_auto_p = true; + return specs; + } n = csc_auto; break; case RID_EXTERN: @@ -12193,6 +12317,11 @@ declspecs_add_scspec (location_t loc, break; case RID_TYPEDEF: n = csc_typedef; + if (specs->c2x_auto_p) + { + error ("%<typedef%> used with %<auto%>"); + specs->c2x_auto_p = false; + } break; default: gcc_unreachable (); @@ -12279,7 +12408,7 @@ finish_declspecs (struct c_declspecs *specs) { gcc_assert (!specs->long_p && !specs->long_long_p && !specs->short_p && !specs->signed_p && !specs->unsigned_p - && !specs->complex_p); + && !specs->complex_p && !specs->c2x_auto_p); /* Set a dummy type. */ if (TREE_CODE (specs->type) == ERROR_MARK) @@ -12315,6 +12444,18 @@ finish_declspecs (struct c_declspecs *specs) "ISO C does not support plain %<complex%> meaning " "%<double complex%>"); } + else if (specs->c2x_auto_p) + { + /* Type to be filled in later, including applying postfix + attributes. This warning only actually appears for + -Wc11-c2x-compat in C2X mode; in older modes, there may + be a warning or pedwarn for implicit "int" instead, or + other errors for use of auto at file scope. */ + pedwarn_c11 (input_location, OPT_Wpedantic, + "ISO C does not support %<auto%> type deduction " + "before C2X"); + return specs; + } else { specs->typespec_word = cts_int; @@ -12331,6 +12472,7 @@ finish_declspecs (struct c_declspecs *specs) specs->explicit_signed_p = specs->signed_p; /* Now compute the actual type. */ + gcc_assert (!specs->c2x_auto_p); switch (specs->typespec_word) { case cts_auto_type: diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 5bdcd93..d70697b 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -2103,7 +2103,11 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, } finish_declspecs (specs); - bool auto_type_p = specs->typespec_word == cts_auto_type; + bool gnu_auto_type_p = specs->typespec_word == cts_auto_type; + bool std_auto_type_p = specs->c2x_auto_p; + bool any_auto_type_p = gnu_auto_type_p || std_auto_type_p; + gcc_assert (!(gnu_auto_type_p && std_auto_type_p)); + const char *auto_type_keyword = gnu_auto_type_p ? "__auto_type" : "auto"; if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { bool handled_assume = false; @@ -2114,8 +2118,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, specs->attrs = handle_assume_attribute (here, specs->attrs, nested); } - if (auto_type_p) - error_at (here, "%<__auto_type%> in empty declaration"); + if (any_auto_type_p) + error_at (here, "%qs in empty declaration", auto_type_keyword); else if (specs->typespec_kind == ctsk_none && attribute_fallthrough_p (specs->attrs)) { @@ -2159,7 +2163,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, shadow_tag_warned (specs, 1); return; } - else if (c_dialect_objc () && !auto_type_p) + else if (c_dialect_objc () && !any_auto_type_p) { /* Prefix attributes are an error on method decls. */ switch (c_parser_peek_token (parser)->type) @@ -2253,6 +2257,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool dummy = false; timevar_id_t tv; tree fnbody = NULL_TREE; + tree std_auto_name = NULL_TREE; /* Declaring either one or more declarators (in which case we should diagnose if there were no declaration specifiers) or a function definition (in which case the diagnostic for @@ -2270,7 +2275,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, c_parser_skip_to_end_of_block_or_statement (parser); return; } - if (auto_type_p && declarator->kind != cdk_id) + if (gnu_auto_type_p && declarator->kind != cdk_id) { error_at (here, "%<__auto_type%> requires a plain identifier" @@ -2278,6 +2283,21 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, c_parser_skip_to_end_of_block_or_statement (parser); return; } + if (std_auto_type_p) + { + struct c_declarator *d = declarator; + while (d->kind == cdk_attrs) + d = d->declarator; + if (d->kind != cdk_id) + { + error_at (here, + "%<auto%> requires a plain identifier, possibly with" + " attributes, as declarator"); + c_parser_skip_to_end_of_block_or_statement (parser); + return; + } + std_auto_name = d->u.id.id; + } if (c_parser_next_token_is (parser, CPP_EQ) || c_parser_next_token_is (parser, CPP_COMMA) || c_parser_next_token_is (parser, CPP_SEMICOLON) @@ -2317,19 +2337,37 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, struct c_expr init; location_t init_loc; c_parser_consume_token (parser); - if (auto_type_p) + if (any_auto_type_p) { init_loc = c_parser_peek_token (parser)->location; rich_location richloc (line_table, init_loc); + unsigned int underspec_state = 0; + if (std_auto_type_p) + underspec_state = start_underspecified_init (init_loc, + std_auto_name); start_init (NULL_TREE, asm_name, global_bindings_p (), &richloc); /* A parameter is initialized, which is invalid. Don't attempt to instrument the initializer. */ int flag_sanitize_save = flag_sanitize; if (nested && !empty_ok) flag_sanitize = 0; - init = c_parser_expr_no_commas (parser, NULL); + if (std_auto_type_p + && c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + { + matching_braces braces; + braces.consume_open (parser); + init = c_parser_expr_no_commas (parser, NULL); + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + braces.skip_until_found_close (parser); + } + else + init = c_parser_expr_no_commas (parser, NULL); + if (std_auto_type_p) + finish_underspecified_init (std_auto_name, underspec_state); flag_sanitize = flag_sanitize_save; - if (TREE_CODE (init.value) == COMPONENT_REF + if (gnu_auto_type_p + && TREE_CODE (init.value) == COMPONENT_REF && DECL_C_BIT_FIELD (TREE_OPERAND (init.value, 1))) error_at (here, "%<__auto_type%> used with a bit-field" @@ -2345,6 +2383,16 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, specs->locations[cdw_typedef] = init_loc; specs->typedef_p = true; specs->type = init_type; + if (specs->postfix_attrs) + { + /* Postfix [[]] attributes are valid with C2X + auto, although not with __auto_type, and + modify the type given by the initializer. */ + specs->postfix_attrs = + c_warn_type_attributes (specs->postfix_attrs); + decl_attributes (&specs->type, specs->postfix_attrs, 0); + specs->postfix_attrs = NULL_TREE; + } if (vm_type) { bool maybe_const = true; @@ -2400,11 +2448,11 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, } else { - if (auto_type_p) + if (any_auto_type_p) { error_at (here, - "%<__auto_type%> requires an initialized " - "data declaration"); + "%qs requires an initialized data declaration", + auto_type_keyword); c_parser_skip_to_end_of_block_or_statement (parser); return; } @@ -2492,11 +2540,11 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, } if (c_parser_next_token_is (parser, CPP_COMMA)) { - if (auto_type_p) + if (any_auto_type_p) { error_at (here, - "%<__auto_type%> may only be used with" - " a single declarator"); + "%qs may only be used with a single declarator", + auto_type_keyword); c_parser_skip_to_end_of_block_or_statement (parser); return; } @@ -2529,10 +2577,11 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, return; } } - else if (auto_type_p) + else if (any_auto_type_p) { error_at (here, - "%<__auto_type%> requires an initialized data declaration"); + "%qs requires an initialized data declaration", + auto_type_keyword); c_parser_skip_to_end_of_block_or_statement (parser); return; } @@ -4213,7 +4262,8 @@ c_parser_direct_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind, if (kind != C_DTR_NORMAL && (c_parser_next_token_starts_declspecs (parser) || (!have_gnu_attrs - && c_parser_nth_token_starts_std_attributes (parser, 1)) + && (c_parser_nth_token_starts_std_attributes (parser, 1) + || c_parser_next_token_is (parser, CPP_ELLIPSIS))) || c_parser_next_token_is (parser, CPP_CLOSE_PAREN))) { struct c_arg_info *args @@ -4489,25 +4539,18 @@ c_parser_parms_list_declarator (c_parser *parser, tree attrs, tree expr, c_parser_consume_token (parser); return ret; } - if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) + if (c_parser_next_token_is (parser, CPP_ELLIPSIS) && !have_gnu_attrs) { struct c_arg_info *ret = build_arg_info (); - if (flag_allow_parameterless_variadic_functions) - { - /* F (...) is allowed. */ - ret->types = NULL_TREE; - } - else - { - /* Suppress -Wold-style-definition for this case. */ - ret->types = error_mark_node; - error_at (c_parser_peek_token (parser)->location, - "ISO C requires a named argument before %<...%>"); - } + ret->types = NULL_TREE; + pedwarn_c11 (c_parser_peek_token (parser)->location, OPT_Wpedantic, + "ISO C requires a named argument before %<...%> " + "before C2X"); c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) { + ret->no_named_args_stdarg_p = true; c_parser_consume_token (parser); return ret; } @@ -17460,7 +17503,7 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, if (nested && c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) break; - if (!first) + if (!first || nested != 2) { if (c_parser_next_token_is (parser, CPP_COMMA)) c_parser_consume_token (parser); @@ -18547,6 +18590,9 @@ c_parser_omp_allocate (location_t loc, c_parser *parser) { tree allocator = NULL_TREE; tree nl = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ALLOCATE, NULL_TREE); + if (c_parser_next_token_is (parser, CPP_COMMA) + && c_parser_peek_2nd_token (parser)->type == CPP_NAME) + c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_NAME)) { matching_parens parens; @@ -18685,7 +18731,6 @@ c_parser_omp_atomic (location_t loc, c_parser *parser, bool openacc) bool structured_block = false; bool swapped = false; bool non_lvalue_p; - bool first = true; tree clauses = NULL_TREE; bool capture = false; bool compare = false; @@ -18696,13 +18741,10 @@ c_parser_omp_atomic (location_t loc, c_parser *parser, bool openacc) while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) { - if (!first - && c_parser_next_token_is (parser, CPP_COMMA) + if (c_parser_next_token_is (parser, CPP_COMMA) && c_parser_peek_2nd_token (parser)->type == CPP_NAME) c_parser_consume_token (parser); - first = false; - if (c_parser_next_token_is (parser, CPP_NAME)) { const char *p @@ -19646,6 +19688,8 @@ 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_INVALID; + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); location_t c_loc = c_parser_peek_token (parser)->location; if (c_parser_next_token_is (parser, CPP_NAME)) { @@ -19722,6 +19766,9 @@ c_parser_omp_flush (c_parser *parser) location_t loc = c_parser_peek_token (parser)->location; c_parser_consume_pragma (parser); enum memmodel mo = MEMMODEL_LAST; + if (c_parser_next_token_is (parser, CPP_COMMA) + && c_parser_peek_2nd_token (parser)->type == CPP_NAME) + c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_NAME)) { const char *p @@ -19814,6 +19861,9 @@ c_parser_omp_scan_loop_body (c_parser *parser, bool open_brace_parsed) c_parser_consume_pragma (parser); + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) { const char *p @@ -20597,9 +20647,14 @@ c_parser_omp_ordered (c_parser *parser, enum pragma_context context, return false; } - if (c_parser_next_token_is (parser, CPP_NAME)) + int n = 1; + if (c_parser_next_token_is (parser, CPP_COMMA)) + n = 2; + + if (c_parser_peek_nth_token (parser, n)->type == CPP_NAME) { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + const char *p + = IDENTIFIER_POINTER (c_parser_peek_nth_token (parser, n)->value); if (!strcmp ("depend", p) || !strcmp ("doacross", p)) { @@ -22472,6 +22527,10 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms) parens.require_close (parser); + if (c_parser_next_token_is (parser, CPP_COMMA) + && c_parser_peek_2nd_token (parser)->type == CPP_NAME) + c_parser_consume_token (parser); + const char *clause = ""; location_t match_loc = c_parser_peek_token (parser)->location; if (c_parser_next_token_is (parser, CPP_NAME)) @@ -22641,7 +22700,9 @@ c_parser_omp_declare_target (c_parser *parser) tree clauses = NULL_TREE; int device_type = 0; bool only_device_type = true; - if (c_parser_next_token_is (parser, CPP_NAME)) + if (c_parser_next_token_is (parser, CPP_NAME) + || (c_parser_next_token_is (parser, CPP_COMMA) + && c_parser_peek_2nd_token (parser)->type == CPP_NAME)) clauses = c_parser_omp_all_clauses (parser, OMP_DECLARE_TARGET_CLAUSE_MASK, "#pragma omp declare target"); else if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) @@ -23062,10 +23123,14 @@ c_parser_omp_declare_reduction (c_parser *parser, enum pragma_context context) initializer.set_error (); if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) bad = true; - else if (c_parser_next_token_is (parser, CPP_NAME) - && strcmp (IDENTIFIER_POINTER + else if (c_parser_next_token_is (parser, CPP_COMMA) + && c_parser_peek_2nd_token (parser)->type == CPP_NAME) + c_parser_consume_token (parser); + if (!bad + && (c_parser_next_token_is (parser, CPP_NAME) + && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), - "initializer") == 0) + "initializer") == 0)) { c_parser_consume_token (parser); pop_scope (); @@ -23258,7 +23323,6 @@ c_parser_omp_declare (c_parser *parser, enum pragma_context context) static void c_parser_omp_requires (c_parser *parser) { - bool first = true; enum omp_requires new_req = (enum omp_requires) 0; c_parser_consume_pragma (parser); @@ -23266,13 +23330,10 @@ c_parser_omp_requires (c_parser *parser) location_t loc = c_parser_peek_token (parser)->location; while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) { - if (!first - && c_parser_next_token_is (parser, CPP_COMMA) + if (c_parser_next_token_is (parser, CPP_COMMA) && c_parser_peek_2nd_token (parser)->type == CPP_NAME) c_parser_consume_token (parser); - first = false; - if (c_parser_next_token_is (parser, CPP_NAME)) { const char *p @@ -23543,7 +23604,6 @@ c_parser_omp_error (c_parser *parser, enum pragma_context context) int at_compilation = -1; int severity_fatal = -1; tree message = NULL_TREE; - bool first = true; bool bad = false; location_t loc = c_parser_peek_token (parser)->location; @@ -23551,13 +23611,10 @@ c_parser_omp_error (c_parser *parser, enum pragma_context context) while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) { - if (!first - && c_parser_next_token_is (parser, CPP_COMMA) + if (c_parser_next_token_is (parser, CPP_COMMA) && c_parser_peek_2nd_token (parser)->type == CPP_NAME) c_parser_consume_token (parser); - first = false; - if (!c_parser_next_token_is (parser, CPP_NAME)) break; @@ -23713,7 +23770,6 @@ c_parser_omp_error (c_parser *parser, enum pragma_context context) static void c_parser_omp_assumption_clauses (c_parser *parser, bool is_assume) { - bool first = true; bool no_openmp = false; bool no_openmp_routines = false; bool no_parallelism = false; @@ -23729,13 +23785,10 @@ c_parser_omp_assumption_clauses (c_parser *parser, bool is_assume) while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) { - if (!first - && c_parser_next_token_is (parser, CPP_COMMA) + if (c_parser_next_token_is (parser, CPP_COMMA) && c_parser_peek_2nd_token (parser)->type == CPP_NAME) c_parser_consume_token (parser); - first = false; - if (!c_parser_next_token_is (parser, CPP_NAME)) break; diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index d787dd4..8116e5c 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -100,6 +100,10 @@ along with GCC; see the file COPYING3. If not see #define C_DECL_COMPOUND_LITERAL_P(DECL) \ DECL_LANG_FLAG_5 (VAR_DECL_CHECK (DECL)) +/* Set on decls used as placeholders for a C2x underspecified object + definition. */ +#define C_DECL_UNDERSPECIFIED(DECL) DECL_LANG_FLAG_7 (DECL) + /* Nonzero for a decl which either doesn't exist or isn't a prototype. N.B. Could be simplified if all built-in decls had complete prototypes (but this is presently difficult because some of them need FILE*). */ @@ -430,6 +434,11 @@ struct c_declspecs { enum-type-specifier;", but such an empty declaration is valid in C2x when "enum identifier;" would not be). */ BOOL_BITFIELD enum_type_specifier_ref_p : 1; + /* Whether "auto" was specified in C2X (or later) mode and means the + type is to be deduced from an initializer, or would mean that if + no type specifier appears later in these declaration + specifiers. */ + BOOL_BITFIELD c2x_auto_p : 1; /* The address space that the declaration belongs to. */ addr_space_t address_space; }; @@ -475,6 +484,8 @@ struct c_arg_info { tree pending_sizes; /* True when these arguments had [*]. */ BOOL_BITFIELD had_vla_unspec : 1; + /* True when the arguments are a (...) prototype. */ + BOOL_BITFIELD no_named_args_stdarg_p : 1; }; /* A declarator. */ @@ -590,6 +601,8 @@ extern bool switch_statement_break_seen_p; extern bool global_bindings_p (void); extern tree pushdecl (tree); +extern unsigned int start_underspecified_init (location_t, tree); +extern void finish_underspecified_init (tree, unsigned int); extern void push_scope (void); extern tree pop_scope (void); extern void c_bindings_start_stmt_expr (struct c_spot_bindings *); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 6c16647..6360984 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -544,17 +544,19 @@ composite_type (tree t1, tree t2) /* Simple way if one arg fails to specify argument types. */ if (TYPE_ARG_TYPES (t1) == NULL_TREE) - { - t1 = build_function_type (valtype, TYPE_ARG_TYPES (t2)); + { + t1 = build_function_type (valtype, TYPE_ARG_TYPES (t2), + TYPE_NO_NAMED_ARGS_STDARG_P (t2)); t1 = build_type_attribute_variant (t1, attributes); return qualify_type (t1, t2); } if (TYPE_ARG_TYPES (t2) == NULL_TREE) - { - t1 = build_function_type (valtype, TYPE_ARG_TYPES (t1)); - t1 = build_type_attribute_variant (t1, attributes); - return qualify_type (t1, t2); - } + { + t1 = build_function_type (valtype, TYPE_ARG_TYPES (t1), + TYPE_NO_NAMED_ARGS_STDARG_P (t1)); + t1 = build_type_attribute_variant (t1, attributes); + return qualify_type (t1, t2); + } /* If both args specify argument types, we must merge the two lists, argument by argument. */ @@ -1702,6 +1704,8 @@ function_types_compatible_p (const_tree f1, const_tree f2, if (args1 == NULL_TREE) { + if (TYPE_NO_NAMED_ARGS_STDARG_P (f1) != TYPE_NO_NAMED_ARGS_STDARG_P (f2)) + return 0; if (!self_promoting_args_p (args2)) return 0; /* If one of these types comes from a non-prototype fn definition, @@ -1715,6 +1719,8 @@ function_types_compatible_p (const_tree f1, const_tree f2, } if (args2 == NULL_TREE) { + if (TYPE_NO_NAMED_ARGS_STDARG_P (f1) != TYPE_NO_NAMED_ARGS_STDARG_P (f2)) + return 0; if (!self_promoting_args_p (args1)) return 0; if (TYPE_ACTUAL_ARG_TYPES (f2) @@ -2855,6 +2861,9 @@ build_external_ref (location_t loc, tree id, bool fun, tree *type) { ref = decl; *type = TREE_TYPE (ref); + if (DECL_P (decl) && C_DECL_UNDERSPECIFIED (decl)) + error_at (loc, "underspecified %qD referenced in its initializer", + decl); } else if (fun) /* Implicit function declaration. */ |