Documentation says [[msvc::forceinline]] is same as __forceinline, but they are not - #5967
Francesco Pretto (ceztko) wants to merge 1 commit into
Conversation
…ut preserves the symbol in the TU The documentation treated [[msvc::forceinline]] as a synonym of __forceinline, but they don't have the same exact behavior. In a empirical test, a Link Time Optimization enabled build of a static library had a method marked as __forceinline elided from the final objects, causing a linking error when trying to consume the static library from a non-LTO enabled exe or shared library. The method definition is *not* present/visible in the header. Instead, [[msvc::forceinline]] was able to both intra-optimize the static library and create a symbol for the annotated function, allowing link from a consumer which has not visibility of the definition. For more context, the behavior of [[msvc::forceinline]] aligns with the behavior of the gcc specific always_inline[1] attribute, and clang also observes the same behavior. Below the results of a probe using VS 2026 and VS 2022. ----------------------------------------------- == toolchains == -- 18 (18.10.12201.205): Visual Studio 18 2026 C:\Program Files\Microsoft Visual Studio\18\Community -- 2022 (17.14.37531.7): Visual Studio 17 2022 C:\Program Files\Microsoft Visual Studio\2022\Community -- cmake: cmake version 4.3.2 == results == VS Annotation LTO Library Exe Shlib Symbols Note ---- --------------------- --- ------- -------------- -------------- -------- ---- 18 none OFF OK LINK-OK RUN-OK LINK-OK RUN-OK present 18 none ON OK LINK-OK RUN-OK LINK-OK RUN-OK n/a (IL) 18 __forceinline OFF OK LINK-FAIL LINK-FAIL absent 18 __forceinline ON OK LINK-FAIL LINK-FAIL n/a (IL) 18 [[msvc::forceinline]] OFF OK LINK-OK RUN-OK LINK-OK RUN-OK present 18 [[msvc::forceinline]] ON OK LINK-OK RUN-OK LINK-OK RUN-OK n/a (IL) 2022 none OFF OK LINK-OK RUN-OK LINK-OK RUN-OK present 2022 none ON OK LINK-OK RUN-OK LINK-OK RUN-OK n/a (IL) 2022 __forceinline OFF OK LINK-FAIL LINK-FAIL absent 2022 __forceinline ON OK LINK-FAIL LINK-FAIL n/a (IL) 2022 [[msvc::forceinline]] OFF OK LINK-OK RUN-OK LINK-OK RUN-OK present 2022 [[msvc::forceinline]] ON OK LINK-OK RUN-OK LINK-OK RUN-OK n/a (IL) == verdict == 18 lto=OFF: PARITY, [[msvc::forceinline]] keeps the symbol where __forceinline drops it 18 lto=ON: PARITY, [[msvc::forceinline]] keeps the symbol where __forceinline drops it 2022 lto=OFF: PARITY, [[msvc::forceinline]] keeps the symbol where __forceinline drops it 2022 lto=ON: PARITY, [[msvc::forceinline]] keeps the symbol where __forceinline drops it ----------------------------------------------- [1] https://gcc.gnu.org/onlinedocs/gcc/Common-Attributes.html#index-always_005finline
|
@microsoft-github-policy-service agree |
|
Francesco Pretto (@ceztko) : Thanks for your contribution! The author(s) and reviewer(s) have been notified to review your proposed change. |
|
Francesco Pretto (@ceztko) : Thanks for your contribution! The author(s) and reviewer(s) have been notified to review your proposed change. |
|
Learn Build status updates of commit 3d44d59: ✅ Validation status: passed
For more details, please refer to the build report. |
|
For more context outside the scope of MSVC, the probe has been tested in gcc/clang, using the gcc specific attribute Linux gcc/clang: MacOs Apple clang: |
|
Can you review the proposed changes? IMPORTANT: When the changes are ready for publication, adding a #label:"aq-pr-triaged" |
|
Thank you for your excellent writeup. Investigating. |
The documentation treated
[[msvc::forceinline]]as a synonym of__forceinline, but they don't have the same exact behavior. In a empirical test, a Link Time Optimization enabled build of a static library had a method marked as__forceinlineelided from the final objects, causing a linking error when trying to consume the static library from a non-LTO enabled exe or shared library. The method definition is not present/visible in the header. Instead,[[msvc::forceinline]]was able to both intra-optimize the static library and create a symbol for the annotated function, allowing link from a consumer which has not visibility of the definition.For more context, the behavior of
[[msvc::forceinline]]aligns with the behavior of the gcc specificalways_inline[1] attribute, and clang also does the same. It's very much desidered, as generating a symbol for external consumers is more flexible than forcely eliding it.Below the results of a probe using VS 2026 and VS 2022. The source (vibe coded with Claude Opus 5) is attached.
inline-probe.zip (updated for non MSVC)
[1] https://gcc.gnu.org/onlinedocs/gcc/Common-Attributes.html#index-always_005finline