else
{
c_inhibit_evaluation_warnings++;
+ in_generic++;
selector = c_parser_expr_no_commas (parser, NULL);
selector = default_function_array_conversion (selector_loc, selector);
c_inhibit_evaluation_warnings--;
+ in_generic--;
+ pop_maybe_used (!flag_isoc23);
if (selector.value == error_mark_node)
{
}
auto_vec<c_generic_association> associations;
+ struct maybe_used_decl *maybe_used_default = NULL;
while (1)
{
struct c_generic_association assoc, *iter;
if (!match)
c_inhibit_evaluation_warnings++;
+ in_generic++;
assoc.expression = c_parser_expr_no_commas (parser, NULL);
if (!match)
c_inhibit_evaluation_warnings--;
+ in_generic--;
+ if (!match)
+ pop_maybe_used (!flag_isoc23);
+ else if (assoc.type == NULL_TREE)
+ maybe_used_default = save_maybe_used ();
+ else
+ pop_maybe_used (true);
if (assoc.expression.value == error_mark_node)
{
c_parser_consume_token (parser);
}
+ if (match_found >= 0 && matched_assoc.type == NULL_TREE)
+ {
+ /* Declarations referenced in the default association are used. */
+ restore_maybe_used (maybe_used_default);
+ pop_maybe_used (true);
+ }
+ else if (maybe_used_default)
+ {
+ /* Declarations referenced in the default association are not used, but
+ are treated as used before C23. */
+ restore_maybe_used (maybe_used_default);
+ pop_maybe_used (!flag_isoc23);
+ }
+
unsigned int ix;
struct c_generic_association *iter;
FOR_EACH_VEC_ELT (associations, ix, iter)
csi_modifiable
};
+/* Record details of decls possibly used inside sizeof or typeof. */
+struct maybe_used_decl
+{
+ /* The decl. */
+ tree decl;
+ /* The level seen at (in_sizeof + in_typeof + in_countof + in_generic). */
+ int level;
+ /* Seen in address-of. */
+ bool address;
+ /* The next one at this level or above, or NULL. */
+ struct maybe_used_decl *next;
+};
+
\f
/* in c-parser.cc */
struct c_tree_token_vec;
extern int in_sizeof;
extern int in_countof;
extern int in_typeof;
+extern int in_generic;
extern bool c_in_omp_for;
extern bool c_omp_array_section_p;
extern tree build_omp_array_section (location_t, tree, tree, tree);
extern tree build_external_ref (location_t, tree, bool, tree *);
extern void pop_maybe_used (bool);
+extern struct maybe_used_decl *save_maybe_used ();
+extern void restore_maybe_used (struct maybe_used_decl *);
extern void mark_decl_used (tree, bool);
extern struct c_expr c_expr_sizeof_expr (location_t, struct c_expr);
extern struct c_expr c_expr_sizeof_type (location_t, struct c_type_name *);
/* The level of nesting inside "typeof". */
int in_typeof;
+/* The level of nesting inside "_Generic". */
+int in_generic;
+
/* True when parsing OpenMP loop expressions. */
bool c_in_omp_for;
return;
/* If we may be in an unevaluated context, delay the decision. */
- if (in_sizeof || in_typeof || in_countof)
+ if (in_sizeof || in_typeof || in_countof || in_generic)
return record_maybe_used_decl (ref, address);
if (static_p)
return ref;
}
-/* Record details of decls possibly used inside sizeof or typeof. */
-struct maybe_used_decl
-{
- /* The decl. */
- tree decl;
- /* The level seen at (in_sizeof + in_typeof + in_countof). */
- int level;
- /* Seen in address-of. */
- bool address;
- /* The next one at this level or above, or NULL. */
- struct maybe_used_decl *next;
-};
-
static struct maybe_used_decl *maybe_used_decls;
-/* Record that DECL, a reference seen inside sizeof or typeof, might be used
- if the operand of sizeof is a VLA type or the operand of typeof is a variably
- modified type. */
+/* Record that DECL, a reference seen inside sizeof or typeof or _Countof or
+ _Generic, might be used if the operand of sizeof is a VLA type or the
+ operand of typeof is a variably modified type or the operand of _Countof has
+ a variable number of elements or the operand of _Generic is the one selected
+ as the result. */
static void
record_maybe_used_decl (tree decl, bool address)
{
struct maybe_used_decl *t = XOBNEW (&parser_obstack, struct maybe_used_decl);
t->decl = decl;
- t->level = in_sizeof + in_typeof + in_countof;
+ t->level = in_sizeof + in_typeof + in_countof + in_generic;
t->address = address;
t->next = maybe_used_decls;
maybe_used_decls = t;
}
-/* Pop the stack of decls possibly used inside sizeof or typeof. If
- USED is false, just discard them. If it is true, mark them used
- (if no longer inside sizeof or typeof) or move them to the next
- level up (if still inside sizeof or typeof). */
+/* Pop the stack of decls possibly used inside sizeof or typeof or _Countof or
+ _Generic. If USED is false, just discard them. If it is true, mark them
+ used (if no longer inside sizeof or typeof or _Countof or _Generic) or move
+ them to the next level up (if still inside sizeof or typeof or _Countof or
+ _Generic). */
void
pop_maybe_used (bool used)
{
struct maybe_used_decl *p = maybe_used_decls;
- int cur_level = in_sizeof + in_typeof + in_countof;
+ int cur_level = in_sizeof + in_typeof + in_countof + in_generic;
while (p && p->level > cur_level)
{
if (used)
maybe_used_decls = p;
}
+/* Pop the stack of decls possibly used inside sizeof or typeof or _Countof or
+ _Generic, without acting on them, and return the pointer to the previous top
+ of the stack. This for use at the end of a default generic association when
+ it is not yet known whether the expression is used. If it later turns out
+ the expression is used (or treated as used before C23), restore_maybe_used
+ should be called on the return value followed by pop_maybe_used (true);
+ otherwise, the return value can be discarded. */
+
+struct maybe_used_decl *
+save_maybe_used ()
+{
+ struct maybe_used_decl *p = maybe_used_decls, *orig = p;
+ int cur_level = in_sizeof + in_typeof + in_countof + in_generic;
+ while (p && p->level > cur_level)
+ p = p->next;
+ maybe_used_decls = p;
+ return orig;
+}
+
+/* Restore the stack of decls possibly used inside sizeof or typeof or _Countof
+ or _Generic returned by save_maybe_used. It is required that the stack is
+ at exactly the point where it was left by save_maybe_used. */
+
+void
+restore_maybe_used (struct maybe_used_decl *stack)
+{
+ maybe_used_decls = stack;
+}
+
/* Return the result of sizeof applied to EXPR. */
struct c_expr
--- /dev/null
+/* Test references to never-defined static functions in _Generic: allowed in
+ certain places for C23 but not before. */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+static int ok1_c23 (); /* { dg-error "used but never defined" } */
+static int ok2_c23 (); /* { dg-error "used but never defined" } */
+static int ok3_c23 (); /* { dg-error "used but never defined" } */
+static int ok4_c23 (); /* { dg-error "used but never defined" } */
+static int ok5_c23 (); /* { dg-error "used but never defined" } */
+static int ok6 ();
+static int ok7 ();
+static int ok8 ();
+static int ok9 ();
+static int ok10 ();
+static int ok11 ();
+static int ok12 ();
+static int not_ok1 (); /* { dg-error "used but never defined" } */
+static int not_ok2 (); /* { dg-error "used but never defined" } */
+
+void
+f ()
+{
+ _Generic (ok1_c23 (), int: 2);
+ _Generic (1, int: 2, default: ok2_c23 ());
+ _Generic (1, default: ok3_c23 (), int: 3);
+ _Generic (1, int: 2, float: ok4_c23 ());
+ _Generic (1, float: ok5_c23 (), int: 3);
+ sizeof (_Generic (ok8 (), int: 2));
+ sizeof (_Generic (1, int: 2, default: ok9 ()));
+ sizeof (_Generic (1, default: ok10 (), int: 3));
+ sizeof (_Generic (1, int: 2, float: ok11 ()));
+ sizeof (_Generic (1, float: ok12 (), int: 3));
+ _Generic (1.0, int: 2, default: not_ok1 ());
+ _Generic (1.0, default: not_ok2 (), int: 3);
+ sizeof (_Generic (1.0, int: 2, default: ok6 ()));
+ sizeof (_Generic (1.0, default: ok7 (), int: 3));
+}
--- /dev/null
+/* Test references to never-defined static functions in _Generic: allowed in
+ certain places for C23 but not before. */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+static int ok1_c23 ();
+static int ok2_c23 ();
+static int ok3_c23 ();
+static int ok4_c23 ();
+static int ok5_c23 ();
+static int ok6 ();
+static int ok7 ();
+static int ok8 ();
+static int ok9 ();
+static int ok10 ();
+static int ok11 ();
+static int ok12 ();
+static int not_ok1 (); /* { dg-error "used but never defined" } */
+static int not_ok2 (); /* { dg-error "used but never defined" } */
+
+void
+f ()
+{
+ _Generic (ok1_c23 (), int: 2);
+ _Generic (1, int: 2, default: ok2_c23 ());
+ _Generic (1, default: ok3_c23 (), int: 3);
+ _Generic (1, int: 2, float: ok4_c23 ());
+ _Generic (1, float: ok5_c23 (), int: 3);
+ sizeof (_Generic (ok8 (), int: 2));
+ sizeof (_Generic (1, int: 2, default: ok9 ()));
+ sizeof (_Generic (1, default: ok10 (), int: 3));
+ sizeof (_Generic (1, int: 2, float: ok11 ()));
+ sizeof (_Generic (1, float: ok12 (), int: 3));
+ _Generic (1.0, int: 2, default: not_ok1 ());
+ _Generic (1.0, default: not_ok2 (), int: 3);
+ sizeof (_Generic (1.0, int: 2, default: ok6 ()));
+ sizeof (_Generic (1.0, default: ok7 (), int: 3));
+}
--- /dev/null
+/* Test references to never-defined static functions in _Generic: still not
+ allowed in a type name used for selection, only an expression (may change if
+ "discarded" is adopted). */
+/* { dg-do compile } */
+/* { dg-options "-std=c2y -pedantic-errors" } */
+
+static int not_ok1 (); /* { dg-error "used but never defined" } */
+
+void
+f ()
+{
+ _Generic (int (*)[not_ok1 ()], default: 1);
+}