Bug: Missing `<intrin.h>` in `winrt.Windows.Foundation.ixx` in module builds

Offen Anfängerfreundlich
#1,646 7 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Maintainer antworten meist innerhalb von 1 Tag

Dieses Issue hat noch niemand übernommen.

Bewertung

Schwierigkeit
2/5
Geschätzter Aufwand
1-3 Stunden
Anfängerfreundlichkeit
72/100
Issue-Typ
Bug
Klarheit
Klar beschrieben
Aktivitätsstatus
Aktiv
Tech-Stack
cpp

Rechercherichtung

Lies das globale Modulfragment in winrt.Windows.Foundation.ixx und vergleiche dessen Includes mit der Verwendung von _InterlockedCompareExchangePointer in Windows.Foundation.h. Füge die fehlende Intrinsic-Deklaration zum Modul-Build hinzu und kompiliere das Windows.Foundation-Modul mit GCC oder Clang, um zu bestätigen, dass der gemeldete Lookup-Fehler behoben ist.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

Version

3.0.260818.1

Summary

In C++20 module builds (-modules), the global module fragment of winrt.Windows.Foundation.ixx does not include <intrin.h>, even though the coroutine helpers in Windows.Foundation.h (winrt::when_any) directly call _InterlockedCompareExchangePointer.

Because <intrin.h> is only included in the global module fragment of winrt_base.ixx and is not exported across modules, _InterlockedCompareExchangePointer has no visible declaration in winrt.Windows.Foundation.ixx:

  • GCC and Clang (targeting MinGW) reject winrt.Windows.Foundation.ixx during template definition lookup.
  • Clang (targeting MSVC) masks this because -fms-extensions treats the intrinsic as a predeclared compiler builtin.
  • MSVC masks this only because an earlier template instantiation in Windows.Foundation.h happens to pull the global module fragment declaration from winrt_base.ifc into scope before winrt::when_any is parsed.

Here is a minimal reproducible example for the msvc compiler bug:

// hidden.h
inline int hidden(int value)
{
    return value;
}

// mod.ixx
module;
#include "hidden.h"

export module provider;

export template <class T>
auto touch(T value)
{
    return hidden(value);
}

// main.cpp
import provider;

int test()
{
    touch(0);          // Instantiating the template leaks `hidden` into scope
    return hidden(42); // MSVC erroneously allows unqualified lookup to find `hidden`
}
Reproducible example
$out = Join-Path $env:TEMP "cppwinrt_intrin_repro"
Remove-Item -Recurse -Force $out -ErrorAction SilentlyContinue
New-Item -ItemType Directory -Force -Path $out | Out-Null
Push-Location $out

# 1. Generate module projection with cppwinrt 3.0.260818.1
$cppwinrt = "$env:USERPROFILE\.nuget\packages\microsoft.windows.cppwinrt\3.0.260818.1\bin\cppwinrt.exe"
& $cppwinrt -in local -out $out -modules -include Windows.Foundation

# Assume upstream fix for `export extern "C"` in winrt/base.h
# $baseH = Get-Content "winrt/base.h" -Raw
# $idx = $baseH.IndexOf('extern "C"')
# Set-Content "winrt/base.h" ($baseH.Substring(0, $idx) + 'export extern "C"' + $baseH.Substring($idx + 10))

# 2. MSVC
$vsDevCmd = "C:\Program Files\Microsoft Visual Studio\18\Community\Common7\Tools\VsDevCmd.bat"
$stdIxx = Get-ChildItem "C:\Program Files\Microsoft Visual Studio\18\Community\VC\Tools\MSVC\*\modules\std.ixx" |
          Select-Object -Last 1 -ExpandProperty FullName
$msvcCmds = @(
    "`"$vsDevCmd`" -arch=x64 -no_logo"
    "cd /d `"$out`""
    "cl /nologo /std:c++20 /EHsc /MD /c /interface /TP `"$stdIxx`" /ifcOutput std.ifc"
    "cl /nologo /std:c++20 /EHsc /MD /I. /c /interface /TP winrt/winrt_numerics.ixx /ifcOutput winrt_numerics.ifc"
    "cl /nologo /std:c++20 /EHsc /MD /I. /c /interface /TP winrt/winrt_base.ixx /reference std=std.ifc /reference winrt_numerics=winrt_numerics.ifc /ifcOutput winrt_base.ifc"
    "cl /nologo /std:c++20 /EHsc /MD /I. /c /interface /TP winrt/winrt.Windows.Foundation.ixx /reference std=std.ifc /reference winrt_numerics=winrt_numerics.ifc /reference winrt_base=winrt_base.ifc /ifcOutput winrt.Windows.Foundation.ifc"
) -join " && "
cmd /c $msvcCmds

# 3. GCC
(Get-Content "winrt/winrt_numerics.ixx" -Raw) -replace '#include <intrin.h>', "#include <x86intrin.h>`n#include <algorithm>`n#include <cmath>`n#include <intrin.h>" | Set-Content "winrt/winrt_numerics.ixx"
(Get-Content "winrt/winrt_base.ixx" -Raw) -replace '#include <intrin.h>', "#include <x86intrin.h>`n#include <intrin.h>" | Set-Content "winrt/winrt_base.ixx"

$stdCc = Get-ChildItem "C:\Tools\msys64\ucrt64\include\c++\*\bits\std.cc" | Select-Object -First 1 -ExpandProperty FullName
g++ -std=c++23 -fmodules -c "$stdCc" -o std.o
g++ -std=c++23 -fmodules -I. -x c++ -c winrt/winrt_numerics.ixx -o winrt_numerics.o
g++ -std=c++23 -fmodules -I. -x c++ -c winrt/winrt_base.ixx -o winrt_base.o
g++ -std=c++23 -fmodules -I. -x c++ -c winrt/winrt.Windows.Foundation.ixx -o winrt.Windows.Foundation.o

Pop-Location

MSVC output:

std.ixx
winrt_numerics.ixx
winrt_base.ixx
winrt.Windows.Foundation.ixx

GCC output when compiling winrt/winrt.Windows.Foundation.ixx:

In file included from winrt/winrt.Windows.Foundation.ixx:102:
./winrt/Windows.Foundation.h: In member function 'void winrt::when_any(const T&, const Rest& ...)::shared_type::operator()(const T&, winrt::Windows::Foundation::AsyncStatus)':
./winrt/Windows.Foundation.h:4217:32: error: there are no arguments to '_InterlockedCompareExchangePointer' that depend on a template parameter, so a declaration of '_InterlockedCompareExchangePointer' must be available [-Wtemplate-body]
 4217 |                 if (nullptr == _InterlockedCompareExchangePointer(reinterpret_cast<void**>(&result), sender_abi, nullptr))
      |                                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

g++ version:

g++ -v
Using built-in specs.
COLLECT_GCC=C:\Tools\msys64\ucrt64\bin\g++.exe
COLLECT_LTO_WRAPPER=C:/Tools/msys64/ucrt64/bin/../lib/gcc/x86_64-w64-mingw32/16.2.0/lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with: ../gcc-16.2.0/configure --prefix=/ucrt64 --with-sysroot=/ucrt64 --with-build-sysroot=D:/M/msys64/ucrt64 --with-local-prefix=/local --with-native-system-header-dir=/include --libexecdir=/ucrt64/lib --enable-bootstrap --enable-checking=release --with-arch=nocona --with-tune=generic --enable-mingw-wildcard --enable-languages=c,c++,ada,fortran,lto,objc,obj-c++,jit --enable-shared --enable-static --enable-libatomic --enable-threads=posix --enable-tls --enable-graphite --enable-fully-dynamic-string --enable-libstdcxx-backtrace=yes --enable-libstdcxx-filesystem-ts --enable-libstdcxx-time --disable-libstdcxx-pch --enable-libgomp --disable-libssp --disable-multilib --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-libiconv --with-system-zlib --with-gmp=/ucrt64 --with-mpfr=/ucrt64 --with-mpc=/ucrt64 --with-isl=/ucrt64 --with-pkgversion='Rev6, Built by MSYS2 project' --with-bugurl=https://github.com/msys2/MINGW-packages/issues --with-gnu-as --with-gnu-ld --with-libstdcxx-zoneinfo=yes --disable-libstdcxx-debug --enable-lto --enable-plugin --with-boot-ldflags=-static-libstdc++ --with-stage1-ldflags=-static-libstdc++
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 16.2.0 (Rev6, Built by MSYS2 project)
Additional comments

winrt_numerics.ixx includes <windowsnumerics.impl.h> directly inside its module purview after pre-including only <directxmath.h> in the global module fragment. However, <windowsnumerics.impl.h> transitively includes standard library headers (<stdexcept> and <limits> in the Windows SDK, and <algorithm> and <cmath> in mingw-w64) inside the module purview, which breaks module builds on libstdc++ and libc++. In addition, the DirectX interop functions (XMLoadFloat2, XMStoreFloat2, etc.) defined in <windowsnumerics.impl.h> sit outside _WINDOWS_NUMERICS_BEGIN_NAMESPACE_, leaving them unexported and attached to the winrt_numerics module even on MSVC.

Vorherrschende Sprache
C++
Sterne
1.9k
Forks
288
Ø Merge
18 Std. 15 Min.
Gemergte PRs (30 T.)
2

Entwicklungsumgebung

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus microsoft/cppwinrt

Alle Issues in microsoft/cppwinrt

Ähnliche Issues

Weitere Issues zu C++

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.