1: Sample code that reproduces the problem
int f(int);
typedef int function_type(int);
typedef function_type *pointer_type;
pointer_type pf = f;
_Static_assert(_Generic(pf, function_type *: 1, default: 0), "pf, function_type *"); // fails
_Static_assert(_Generic(pf, pointer_type: 1, default: 0), "pf, pointer_type"); // passes
_Static_assert(_Generic(&f, function_type *: 1, default: 0), "&f, function_type *"); // passes
_Static_assert(_Generic(&f, pointer_type: 1, default: 0), "&f, pointer_type"); // fails
2: Exact command used to run SDCC on this sample code
sdcc -c --std=c11 bug.c
3: SDCC version tested (type "sdcc -v" to find it)
SDCC : mcs51/z80/z180/r2k/r2ka/r3ka/r4k/r5k/r6k/sm83/tlcs90/ez80/z80n/r800/ds390/pic16/pic14/TININative/ds400/hc08/s08/stm8/pdk13/pdk14/pdk15/mos6502/mos65c02/huc6280/f8/f8l TD- 4.6.2 #0 (macOS ARM64)
published under GNU General Public License (GPL)
4: Copy of the error message or incorrect output, or a clear description of the observed versus expected behavior.
SDCC reports two out of three assertion failures:
bug.c:6: warning 215: static assertion failed: "pf, function_type *"
bug.c:9: warning 215: static assertion failed: "&f, pointer_type"
GCC 16.1.0 and Clang 23.1.0 do not report any assertion failures, which is the expected behaviour:
https://godbolt.org/z/rnG4av3Ts
Text edited by @spth to fix code section highlighting.
I can't fix the formatting myself
addSymChainin SDCCsymt.c callschangePointer, which changes pointers to functions that do not use banked calls to typeCPOINTER. This happens for the declarations ofpointer_typeandpf.checkDeclalso callschangePointer, but typedefs bypass that call.For the generic associations with
function_type *, thetype_namerule in SDCC.y callspointerTypesandprocessFuncPtr, without callingchangePointer.pointerTypesusesport->unqualified_pointer, which leaves the type asGPOINTERon the tested targets.For the generic associations with
pointer_type, thetype_namerule uses thespecifier_qualifier_list-only alternative. It uses the complete pointer type already processed bychangePointerwhen thetypedefwas declared, so these association types remainCPOINTER.The
GENERICcase inSDCCast.cmutates a copy of pointers markedDCL_TYPE_IMPLICITINTRINSIC, which becomes typeGPOINTER. This affects the controlling expression&fin the example, whereas the declared pointer object's type remainsCPOINTER.Presumably function pointer types should be canonicalised before comparison, but I don't know enough about address spaces and other SDCC-specific features to be sure how to do that correctly.
AFAIR, for a similar issue with objects, we introduced the sclass_implicitintrinsic flag as a hack to mark where a named address space had been assigned implicitly, and should be ignored for
_Generic. Maybe the easiest solution would be to check if that would work for functions, too (and probably was just forgotten to implement then)?Hi Philipp,
Please find a candidate fix for this bug attached. It's a standalone patch for r16960 with no dependencies.
The existing implicit-address-space handling already affects
&f: its pointer type hasDCL_TYPE_IMPLICITINTRINSICset, so theGENERICcase ofdecorateTypechanges its pointer kind fromCPOINTERtoGPOINTER.The declaration of
pf, however, goes throughchangePointer, which sets its pointer kind toCPOINTERwithout setting that flag. The pointer type recorded forpfdoes not haveDCL_TYPE_IMPLICITINTRINSIC, so_Genericdoes not reset its pointer kind toGPOINTER. The typedef declaration ofpointer_typegoes through the same processing aspf, so using that typedef name in an association likewise supplies aCPOINTERtype.The abstract association type
function_type *takes a different path:pointerTypesassignsGPOINTERon the affected targets, andprocessFuncPtrdoes not callchangePointerto convert it toCPOINTER.The patch adds
changePointerafter the existing flag handling in theGENERICcase ofdecorateTypeinSDCCast.c, and insideprocessFuncPtrinSDCCsymt.c. Thus the types ofpfand&f, and the association typesfunction_type *andpointer_type, all useCPOINTERinternally and match as expected.Last edit: Christopher Bazley 2026-10-09
Diff:
Please consider the revised patch that I am now attaching instead of the version previously attached.
This revision moves the
_Genericandsizeofchecks to compile-time assertions in valdiag. They check types and never call a function. The duplicate-association checks remain, and the compiler fix is unchanged.Last edit: Christopher Bazley 2026-10-14
The patch looks good to me.
Fixed in [r17018].
Related
Commit: [r17018]
Test fails for mcs51-huge
Thanks for highlighting the regression. It should be fixed by [r17029].
Related
Commit: [r17029]