https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55881
--- Comment #7 from Manuel López-Ibáñez <manu at gcc dot gnu.org> --- Some comments from a discussion with Martin and David: %G and %K sometimes do not work with pragma diagnostics. The reason is that the pragma diagnostics check is done here: https://github.com/gcc-mirror/gcc/blob/a0e9bfbb865dcaf307a4a06a29a7e1e7be24ee15/gcc/diagnostic.c#L944 which is processed earlier than the %G and %K formats. If we have something like: warning_at(loc, "%K", exp) there is one case when it should work (otherwise something is really broken): when loc == EXPR_LOCATION(exp) and loc points to a location that is affected by the #pragma. And two cases when it will not work: Case #1. loc != EXPR_LOCATION(exp) and loc is pointing to a location not affected by the #pragma but EXPR_LOCATION(exp) is pointing to a location affected by the #pragma. Case #2. loc == EXPR_LOCATION(exp) and loc is pointing to a location not affected by the #pragma but some location in the inlining stack is affected by the #pragma. I would say that every case #1 is a bug. The fix is to always make sure that loc == TREE_LOCATION(exp). I see in builtins.c code like: location_t loc = tree_nonartificial_location (exp); loc = expansion_point_location_if_in_system_header (loc); warning_at (loc, opt, "%K%qD specified bound %E " "exceeds maximum object size %E", exp, func, range[0], maxobjsize); This is likely to break, because "loc", that is, expansion_point_location_if_in_system_header (tree_nonartificial_location (exp)), is used for evaluating the #pragma but %K (that is, EXPR_LOCATION(exp)) is used for printing the source location, and those two may not be equal in some cases. Fixing this is trivial but fragile. Just make sure that "loc" in warning_at(loc) is always "EXPR_LOCATION(exp)", but this is fragile. The real fix is to replace %K and %G with an explicit location. For replacing %K and %G (and also for fixing case #2), we need to process the inlining stack before calling update_effective_level_from_pragmas(). And we probably need to decide what level takes precedence in cases such as: https://godbolt.org/z/YXA_vG In constructor 'BadString3<N>::BadString3(const char*, size_t) [with long unsigned int N = 3]', inlined from 'void bad3_warn_size_m1_var(const char*)' at <source>:30:23, inlined from 'void call_bad3_warn_size_m1_var()' at <source>:37:25: <source>:21:13: warning: 'char* strncpy(char*, const char*, size_t)' output truncated before terminating nul copying 3 bytes from a string of the same length [-Wstringop-truncation] If I place the pragma ignored around line 21. The diagnostic is silenced as it should be. But if I place it around line 30, it is not. I think it makes sense that the outermost #pragmas override inner-most #pragmas, since the inner-most affects more places than the outer-most. But there may be cases I haven't thought about. In any case, I see two ways to fix case #2 (and remove completely %G and %K): Solution 1: Have new variants warning_K and error_K (better names needed or overloads?) of warning_at and error_at that can take a tree, do what percent_K_format does, in particular, set *pp_ti_abstract_origin (text) (or even better, set diagnostic_abstract_origin (diagnostic)), and then walk the abstract_origin chain to extract the locations as done here (https://github.com/gcc-mirror/gcc/blob/cba058c7d596cf482254e7a2d7492eec29553a9c/gcc/langhooks.c#L407) and save it somewhere in the diagnostic_info or context. Then, call into diagnostic.c (diagnostic_report_diagnostic) and make update_effective_level_from_pragmas() handle multiple locations. Solution 2: Provide a function (or constructor) that somehow encodes the abstract_origin chain in the rich locations and that must be called explicitly before calling warning/error_at using this rich_location, then handle the abstract_origin chain within diagnostic.c as in solution 1. Something like: rich_location ao_loc(EXPR_LOCATION (t), TREE_BLOCK (t)); warning_at(ao_loc,""); Both solutions will remove completely the need for %K and percent_K_format. Solution 1 could also be an intermediate step until there is a way to encode the abstract_origin chain in a rich_location.