diff --git a/regression/ansi-c/_Generic_array_typedef/main.c b/regression/ansi-c/_Generic_array_typedef/main.c new file mode 100644 index 00000000000..4d2c89eb27f --- /dev/null +++ b/regression/ansi-c/_Generic_array_typedef/main.c @@ -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; +} \ No newline at end of file diff --git a/regression/ansi-c/_Generic_array_typedef/test.desc b/regression/ansi-c/_Generic_array_typedef/test.desc new file mode 100644 index 00000000000..bb4ed85cb69 --- /dev/null +++ b/regression/ansi-c/_Generic_array_typedef/test.desc @@ -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 diff --git a/regression/ansi-c/_Generic_pointer_to_array/main.c b/regression/ansi-c/_Generic_pointer_to_array/main.c new file mode 100644 index 00000000000..9fc20ada780 --- /dev/null +++ b/regression/ansi-c/_Generic_pointer_to_array/main.c @@ -0,0 +1,34 @@ +#include +#include + +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; +} diff --git a/regression/ansi-c/_Generic_pointer_to_array/test.desc b/regression/ansi-c/_Generic_pointer_to_array/test.desc new file mode 100644 index 00000000000..db05cffae9f --- /dev/null +++ b/regression/ansi-c/_Generic_pointer_to_array/test.desc @@ -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. diff --git a/src/ansi-c/c_typecheck_expr.cpp b/src/ansi-c/c_typecheck_expr.cpp index b5799f315f3..9cb82bb71ea 100644 --- a/src/ansi-c/c_typecheck_expr.cpp +++ b/src/ansi-c/c_typecheck_expr.cpp @@ -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) @@ -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) @@ -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(irep.find(ID_value)); - else if(op_type == static_cast(irep.find(ID_type_arg))) + else { - assoc_match = static_cast(irep.find(ID_value)); + const typet &assoc_type = + static_cast(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(irep.find(ID_value)); + } } }