Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions regression/ansi-c/_Generic_array_typedef/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Test case for _Generic with array typedef
// This should reproduce the issue from GitHub issue #8243

typedef struct m_string_s
{
int s, a;
char *ptr;
} m_string_t[1];

#define TEST_GENERIC(x) \
_Generic((x), struct m_string_s * : 42, int : 1, float : 2, default : 99)

int main(void)
{
m_string_t s; // Array type that should decay to pointer
int i = 5;
float f = 3.14f;
char c = 'x';

// Test that array typedef matches pointer type due to array-to-pointer decay
assert(TEST_GENERIC(s) == 42); // Should match struct m_string_s *

// Test that other types work as expected
assert(TEST_GENERIC(i) == 1); // Should match int
assert(TEST_GENERIC(f) == 2); // Should match float
assert(TEST_GENERIC(c) == 99); // Should match default (char)

return 0;
}
9 changes: 9 additions & 0 deletions regression/ansi-c/_Generic_array_typedef/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
CORE
main.c

^EXIT=0$
^SIGNAL=0$
--
^warning: ignoring
--
_Generic with array typedef should match pointer type due to array decay
34 changes: 34 additions & 0 deletions regression/ansi-c/_Generic_pointer_to_array/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include <assert.h>
#include <stdbool.h>

int main(void)
{
// Test case from issue #8690
// A generic selection on a value of type int(*)[5] should match an arm for int(*)[]
int arr[5];
assert(_Generic(&arr, int(*)[] : true));

// Additional test cases to ensure compatibility matching works correctly

// Test with different array sizes - should all match int(*)[]
int arr2[10];
assert(_Generic(&arr2, int(*)[] : true));

int arr3[1];
assert(_Generic(&arr3, int(*)[] : true));

// Test with character arrays
char carr[20];
assert(_Generic(&carr, char(*)[] : true, default : false));

// Test with default case as fallback
int *ptr;
int result = _Generic(ptr, int(*)[] : 1, default : 2);
assert(result == 2);

// Test pointer to array of specific size should also work
int(*ptr_to_arr)[5] = &arr;
assert(_Generic(ptr_to_arr, int(*)[] : true));

return 0;
}
11 changes: 11 additions & 0 deletions regression/ansi-c/_Generic_pointer_to_array/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
CORE
main.c

^EXIT=0$
^SIGNAL=0$
--
^warning: ignoring
^CONVERSION ERROR$
--
Test _Generic selection with pointer-to-array types (issue #8690).
Pointer to array with specified size should match pointer to array with unspecified size.
39 changes: 34 additions & 5 deletions src/ansi-c/c_typecheck_expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,23 @@ bool c_typecheck_baset::gcc_types_compatible_p(
else if(type1.id()==ID_array &&
type2.id()==ID_array)
{
return gcc_types_compatible_p(
to_array_type(type1).element_type(),
to_array_type(type2).element_type()); // ignore size
// For C11 6.2.7: array types are compatible if element types are
// compatible and both size specifiers are present and equal, OR
// one or both size specifiers are absent.
if(!gcc_types_compatible_p(
to_array_type(type1).element_type(),
to_array_type(type2).element_type()))
return false;

const array_typet &a_type1 = to_array_type(type1);
const array_typet &a_type2 = to_array_type(type2);

// If either size is absent (incomplete), arrays are compatible
if(!a_type1.is_complete() || !a_type2.is_complete())
return true;

// Both sizes are present - they must be equal
return a_type1.size() == a_type2.size();
}
else if(type1.id()==ID_code &&
type2.id()==ID_code)
Expand All @@ -156,6 +170,12 @@ bool c_typecheck_baset::gcc_types_compatible_p(

return true;
}
else if(
type1.id() == ID_array &&
type2 == pointer_type(to_array_type(type1).element_type()))
{
return true;
}
else
{
if(type1==type2)
Expand Down Expand Up @@ -463,9 +483,18 @@ void c_typecheck_baset::typecheck_expr_main(exprt &expr)
{
if(irep.get(ID_type_arg) == ID_default)
default_match = static_cast<const exprt &>(irep.find(ID_value));
else if(op_type == static_cast<const typet &>(irep.find(ID_type_arg)))
else
{
assoc_match = static_cast<const exprt &>(irep.find(ID_value));
const typet &assoc_type =
static_cast<const typet &>(irep.find(ID_type_arg));
// Use type compatibility matching instead of exact equality.
// This allows pointer-to-array types with specified dimensions
// to match pointer-to-array types with unspecified dimensions,
// which is required by C11 6.5.1.1 Generic selection.
if(gcc_types_compatible_p(op_type, assoc_type))
{
assoc_match = static_cast<const exprt &>(irep.find(ID_value));
}
}
}

Expand Down
Loading