https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86202
--- Comment #3 from Richard Biener <rguenth at gcc dot gnu.org> --- The issue is that the frontend ends up with <function_decl 0x7ffff6939200 memcpy type <function_type 0x7ffff69bd690 ... arg-types <tree_list 0x7ffff69ba938 value <pointer_type 0x7ffff68b4000> chain <tree_list 0x7ffff69ba910 value <pointer_type 0x7ffff68b4000> chain <tree_list 0x7ffff69ba8e8 value <pointer_type 0x7ffff68b8e70> chain <tree_list 0x7ffff68a8820 value <void_type 0x7ffff68acf18 void>>>>> ^^^ pointer_to_this <pointer_type 0x7ffff69bd9d8>> addressable used nothrow public external built-in decl_3 decl_5 QI t.c:1:7 align:8 warn_if_not_align:0 built-in: BUILT_IN_NORMAL:BUILT_IN_MEMCPY context <translation_unit_decl 0x7ffff68a1258 t.c> ^^^ so it puts BUILT_IN_NORMAL:BUILT_IN_MEMCPY on a decl with argument types that do not match that of the MEMCPY builtin. I think this is a more general issue with decl merging and not an issue of rejecting incompatible declarations. If we accept _any_ mismatch then we need to keep two decls and _not_ merge them. Note that the original builtin decl is still there and it does have the correct types. So eventually the only issue is that we set the BUILT_IN_NORMAL:BUILT_IN_MEMCPY attribution to mismatched decls.