Skip to content

Commit e0bc21c

Browse files
committed
Fix _Generic selection for pointer-to-array types
Use type compatibility matching instead of exact equality in _Generic. Also fix array type compatibility check to follow C11 6.2.7 standard: Arrays with unspecified size are compatible with specified sizes. Fixes: #8690
1 parent 4fe3ade commit e0bc21c

File tree

3 files changed

+73
-5
lines changed

3 files changed

+73
-5
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#include <assert.h>
2+
#include <stdbool.h>
3+
4+
int main(void)
5+
{
6+
// Test case from issue #8690
7+
// A generic selection on a value of type int(*)[5] should match an arm for int(*)[]
8+
int arr[5];
9+
assert(_Generic(&arr, int(*)[] : true));
10+
11+
// Additional test cases to ensure compatibility matching works correctly
12+
13+
// Test with different array sizes - should all match int(*)[]
14+
int arr2[10];
15+
assert(_Generic(&arr2, int(*)[] : true));
16+
17+
int arr3[1];
18+
assert(_Generic(&arr3, int(*)[] : true));
19+
20+
// Test with character arrays
21+
char carr[20];
22+
assert(_Generic(&carr, char(*)[] : true, default : false));
23+
24+
// Test with default case as fallback
25+
int *ptr;
26+
int result = _Generic(ptr, int(*)[] : 1, default : 2);
27+
assert(result == 2);
28+
29+
// Test pointer to array of specific size should also work
30+
int(*ptr_to_arr)[5] = &arr;
31+
assert(_Generic(ptr_to_arr, int(*)[] : true));
32+
33+
return 0;
34+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
main.c
3+
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
--
7+
^warning: ignoring
8+
^CONVERSION ERROR$
9+
--
10+
Test _Generic selection with pointer-to-array types (issue #8690).
11+
Pointer to array with specified size should match pointer to array with unspecified size.

src/ansi-c/c_typecheck_expr.cpp

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,23 @@ bool c_typecheck_baset::gcc_types_compatible_p(
130130
else if(type1.id()==ID_array &&
131131
type2.id()==ID_array)
132132
{
133-
return gcc_types_compatible_p(
134-
to_array_type(type1).element_type(),
135-
to_array_type(type2).element_type()); // ignore size
133+
// For C11 6.2.7: array types are compatible if element types are
134+
// compatible and both size specifiers are present and equal, OR
135+
// one or both size specifiers are absent.
136+
if(!gcc_types_compatible_p(
137+
to_array_type(type1).element_type(),
138+
to_array_type(type2).element_type()))
139+
return false;
140+
141+
const array_typet &a_type1 = to_array_type(type1);
142+
const array_typet &a_type2 = to_array_type(type2);
143+
144+
// If either size is absent (incomplete), arrays are compatible
145+
if(!a_type1.is_complete() || !a_type2.is_complete())
146+
return true;
147+
148+
// Both sizes are present - they must be equal
149+
return a_type1.size() == a_type2.size();
136150
}
137151
else if(type1.id()==ID_code &&
138152
type2.id()==ID_code)
@@ -463,9 +477,18 @@ void c_typecheck_baset::typecheck_expr_main(exprt &expr)
463477
{
464478
if(irep.get(ID_type_arg) == ID_default)
465479
default_match = static_cast<const exprt &>(irep.find(ID_value));
466-
else if(op_type == static_cast<const typet &>(irep.find(ID_type_arg)))
480+
else
467481
{
468-
assoc_match = static_cast<const exprt &>(irep.find(ID_value));
482+
const typet &assoc_type =
483+
static_cast<const typet &>(irep.find(ID_type_arg));
484+
// Use type compatibility matching instead of exact equality.
485+
// This allows pointer-to-array types with specified dimensions
486+
// to match pointer-to-array types with unspecified dimensions,
487+
// which is required by C11 6.5.1.1 Generic selection.
488+
if(gcc_types_compatible_p(op_type, assoc_type))
489+
{
490+
assoc_match = static_cast<const exprt &>(irep.find(ID_value));
491+
}
469492
}
470493
}
471494

0 commit comments

Comments
 (0)