Bug 114423 - Incorrectly placed caret in the message about expanded _Pragma
Summary: Incorrectly placed caret in the message about expanded _Pragma
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: preprocessor (show other bugs)
Version: 14.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
Keywords: diagnostic
Depends on:
Reported: 2024-03-21 22:20 UTC by Centurion
Modified: 2024-03-22 18:28 UTC (History)
1 user (show)

See Also:
Known to work:
Known to fail:
Last reconfirmed: 2024-03-21 00:00:00

test (57 bytes, text/plain)
2024-03-21 22:20 UTC, Centurion

Note You need to log in before you can comment on or make changes to this bug.
Description Centurion 2024-03-21 22:20:58 UTC
Created attachment 57762 [details]

Diagnostics working with _Pragma from macro puts a caret in position same as directly inside the macro.
_Pragma("GCC error \"message\"")

#define err \
_Pragma("GCC error \"message\"")


gcc -E:
<source>:1:11: error: message
    1 | _Pragma("GCC error \"message\"")
      |           ^~~~~~~~~
<source>:6:11: error: message
    6 | err
      |           ^
Comment 1 Andrew Pinski 2024-03-21 22:24:27 UTC

clang produces:
<source>:2:1: error: message
    2 | _Pragma("GCC error \"message\"")
      | ^
<scratch space>:2:6: note: expanded from here
    2 |  GCC error "message"
      |      ^
<source>:7:1: error: message
    7 | err
      | ^
<source>:4:13: note: expanded from macro 'err'
    4 | #define err \
      |             ^
<scratch space>:4:6: note: expanded from here
    4 |  GCC error "message"
      |      ^

I wonder if GCC is doing something similar to get the column info and then still using the original line.
Comment 2 Lewis Hyatt 2024-03-22 14:48:56 UTC
libcpp is unfortunately not equipped to get valid locations when it lexes from a _Pragma string. (It thinks it is lexing from a file as normal.) The locations are wrong even without macros involved. The current situation is that we produce invalid locations (that happen to usually be close to reasonable, without macros, although they will be off by a few columns usually) for all the tokens, then after lexing the tokens, we replace all of their locations with the (valid) location of the _Pragma operator. This is good enough to make _Pragma("GCC diagnostic") work and do the right thing (after many bug fixes over the years), which has been the primary focus. But it means that any diagnostics generated by libcpp during lexing itself have bad locations.

I submitted a rather large patch series a couple years ago that fixed it comprehensively. The bulk of it is that the line_map class needs to be able to handle locations for data that exist in memory and not in any file. Then all code that uses line_map locations and all diagnostics code needs to be aware of that concept and support it. The thread was left off here, for reference: https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628290.html with the last full patchset I sent being at https://gcc.gnu.org/pipermail/gcc-patches/2023-August/626885.html. It worked fine then, however a lot of interfaces have been changed since that time, and so it would need to be rebased extensively now.

FWIW, with the above-linked patch series, on this example we output:
In buffer generated from t.cpp:1:
<generated>:1:11: error: message
    1 | GCC error "message"
      |           ^~~~~~~~~
t.cpp:1:1: note: in <_Pragma directive>
    1 | _Pragma("GCC error \"message\"")
      | ^~~~~~~
In buffer generated from t.cpp:6:
<generated>:1:11: error: message
    1 | GCC error "message"
      |           ^~~~~~~~~
t.cpp:4:1: note: in <_Pragma directive>
    4 | _Pragma("GCC error \"message\"")
      | ^~~~~~~
t.cpp:6:1: note: in expansion of macro ‘err’
    6 | err
      | ^~~

I am not sure why I stopped getting responses to that patch series. I was disinclined to ping it further because I worried that it was perhaps deemed too large and invasive, to fix what ends up being a rather minor problem in practice? I think it would be doable to handle it with a more incremental approach... we could at least achieve that diagnostics generated during lexing get assigned to the valid location of the _Pragma operator instead of an invalid one.