aboutsummaryrefslogtreecommitdiff
path: root/gcc/c
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2022-11-07 08:24:48 +0100
committerMartin Liska <mliska@suse.cz>2022-11-07 08:24:48 +0100
commit1b09b78ee61bd921ae78ebd0f7905b95b9e1c903 (patch)
tree9c04b59cdd2cd460f0727501d15402d31ffcf5a4 /gcc/c
parent1eb021edb27e26f95cda63df121f6bc951647599 (diff)
parentc4f8f8afd07680f9e718de1331cd09607bdd9ac8 (diff)
downloadgcc-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/ChangeLog103
-rw-r--r--gcc/c/c-decl.cc156
-rw-r--r--gcc/c/c-parser.cc167
-rw-r--r--gcc/c/c-tree.h13
-rw-r--r--gcc/c/c-typeck.cc23
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. */