Skip to content

Conformant libc++21 formatter refactor (boundary widening) [WIP]#41072

Closed
benhillis wants to merge 1 commit into
microsoft:masterfrom
benhillis:libcxx21-formatter-conformant
Closed

Conformant libc++21 formatter refactor (boundary widening) [WIP]#41072
benhillis wants to merge 1 commit into
microsoft:masterfrom
benhillis:libcxx21-formatter-conformant

Conversation

@benhillis

Copy link
Copy Markdown
Member

Draft / WIP. Follow-up to #41071 (which ships the minimal #ifdef WIN32 guard as the shipping fix).

This branch explores the fully conformant alternative: instead of keeping the formatter<char*, wchar_t> / formatter<std::string, wchar_t> specializations (deleted in C++20/23 [format.formatter.spec] and shipped as deleted specializations in libc++ 20+), it removes them and widens narrow arguments explicitly.

Approach

The key insight is a single boundary helper rather than per-call-site churn:

  • wsl::shared::string::LocalizationArg() (stringshared.h) widens narrow string args (const char*, char[N], std::string, std::string_view) to wchar_t on Windows, and is an identity forward on Linux (where messages are already narrow).
  • The Localization generator (generateLocalizationHeader.ps1) routes every Message*() argument through it, so std::vformat(message, ARGS(LocalizationArg(arg)...)).

This fixes all product code (common, wslc, wslcsession, service.exe) through one generator change.

Remaining work

Copilot AI review requested due to automatic review settings July 13, 2026 23:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR explores a C++20/23-conformant approach to formatting localized messages in the presence of libc++21’s deleted cross-encoding std::formatter specializations by removing the repo’s narrow→wide formatters and instead widening narrow arguments at a single boundary.

Changes:

  • Updated the localization header generator to route every Message*() formatting argument through wsl::shared::string::LocalizationArg().
  • Introduced LocalizationArg() and removed the repo’s std::formatter<char*/*, wchar_t>-style specializations, plus updated several call sites to explicitly widen narrow strings where needed.
  • Bumped Microsoft.WSL.LinuxSdk from 1.20.0 to 1.23.0.

Reviewed changes

Copilot reviewed 30 out of 30 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
tools/generateLocalizationHeader.ps1 Routes generated Message*() formatting arguments through LocalizationArg() before std::vformat.
src/shared/inc/stringshared.h Adds LocalizationArg() boundary helper; removes narrow→wide formatter specializations; updates source_location wide formatting.
src/windows/common/ExecutionContext.h Normalizes user-error message conversion via ToUserErrorMessage() instead of formatting-based coercion.
src/windows/wslcsession/WSLCVolumes.cpp Explicitly widens narrow args passed into localized warnings/errors.
src/windows/wslcsession/WSLCVirtualMachine.cpp Explicitly widens narrow port-string argument for localized error.
src/windows/wslcsession/WSLCVhdVolume.cpp Explicitly widens several narrow args in localized errors/warnings.
src/windows/wslcsession/WSLCSession.cpp Widens narrow identifiers/names passed into localized user errors.
src/windows/wslcsession/WSLCGuestVolume.cpp Widens narrow option strings used in localized error paths.
src/windows/wslcsession/WSLCContainer.cpp Widens various narrow IDs/names used in localized user errors/warnings.
src/windows/wslcsession/OptionParser.cpp Widens option key/value strings for localized user errors.
src/windows/wslc/tasks/VolumeTasks.cpp Widens volume names printed via localized messages.
src/windows/wslc/tasks/NetworkTasks.cpp Widens network names printed via localized messages.
src/windows/wslc/tasks/ImageTasks.cpp Widens image IDs/refs for localized output; widens ID printing in list path.
src/windows/wslc/tasks/ContainerTasks.cpp Widens container IDs printed via localized messages.
src/windows/wslc/services/SessionService.cpp Widens command name passed into localized launch-failure error.
src/windows/wslc/services/ImageService.cpp Widens image reference passed into localized tag-format error.
src/windows/wslc/services/ImageProgressCallback.cpp Fixes direct wide std::format uses by widening LPCSTR inputs.
src/windows/wslc/commands/VersionCommand.cpp Fixes wide std::format call by widening WSL_PACKAGE_VERSION.
src/windows/service/exe/WslCoreVm.cpp Widens enum-to-string values before passing to localized warning.
src/windows/service/exe/LxssUserSession.cpp Widens JSON parse error text; adjusts error-string handling for localized warning.
src/windows/common/wslutil.cpp Widens Windows version / IP / image strings passed into localized messages.
src/windows/common/WslCoreConfig.cpp Widens config key/value strings passed into localized warnings.
src/windows/common/WslClient.cpp Widens strerror/version/build-info narrow inputs used in localized output.
src/windows/common/string.cpp Ensures hex-string invalid input is widened appropriately for localized error formatting.
src/windows/common/notifications.cpp Widens binaryName passed into localized toast content.
src/windows/common/ConsommeNetworking.cpp Widens host address string in wide std::format call.
src/shared/inc/JsonUtils.h Widens exception message for localized invalid-JSON user error on Windows.
src/shared/configfile/configfile.h Widens enum-parse warning arguments before calling localization.
src/shared/configfile/configfile.cpp Widens multiple config warning arguments before calling localization.
packages.config Updates Linux SDK NuGet version to 1.23.0 (and introduces a leading BOM).

Comment thread src/shared/configfile/configfile.cpp Outdated
Comment on lines 67 to 69
EMIT_USER_WARNING(Localization::MessageConfigInvalidBoolean(
wsl::shared::string::MultiByteToWide(value), wsl::shared::string::MultiByteToWide(name), filePath, fileLine));
return false;
Comment thread src/shared/configfile/configfile.cpp Outdated
Comment on lines 82 to 84
EMIT_USER_WARNING(Localization::MessageConfigInvalidInteger(
wsl::shared::string::MultiByteToWide(value), wsl::shared::string::MultiByteToWide(name), filePath, fileLine));
return false;
Comment thread src/shared/configfile/configfile.cpp Outdated
Comment on lines 102 to 104
EMIT_USER_WARNING(wsl::shared::Localization::MessageInvalidNumberString(
wsl::shared::string::MultiByteToWide(value), wsl::shared::string::MultiByteToWide(name), filePath, fileLine));
return false;
Comment thread src/shared/configfile/configfile.cpp Outdated
Comment on lines +197 to +203
EMIT_USER_WARNING(Localization::MessageConfigKeyDuplicated(
wsl::shared::string::MultiByteToWide(name),
fileName,
line,
wsl::shared::string::MultiByteToWide(m_parseResult->first),
fileName,
m_parseResult->second));
Comment thread src/shared/configfile/configfile.cpp Outdated
Comment on lines 227 to 228
EMIT_USER_WARNING(Localization::MessageConfigUnknownKey(wsl::shared::string::MultiByteToWide(keyName), filePath, fileLine));
return;
Comment thread src/shared/configfile/configfile.h Outdated
Comment on lines +147 to +152
EMIT_USER_WARNING(wsl::shared::Localization::MessageConfigInvalidEnum(
wsl::shared::string::MultiByteToWide(value),
wsl::shared::string::MultiByteToWide(name),
fileName,
line,
wsl::shared::string::MultiByteToWide(validValues.str())));
Comment on lines +682 to +685
if constexpr (std::is_same_v<std::remove_cvref_t<T>, std::string> || std::is_same_v<std::remove_cvref_t<T>, std::string_view>)
{
return MultiByteToWide(std::string{value});
}
Copilot AI review requested due to automatic review settings July 14, 2026 03:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 43 out of 43 changed files in this pull request and generated 3 comments.

Comment on lines +111 to +112
# Widen narrow arguments once into lifetime-extended locals so make_[w]format_args (which
# requires lvalues) can bind to them. LocalizationArg is identity on non-narrow types.
Comment on lines 3 to 6
#pragma once

#include "wslutil.h"

Comment thread packages.config
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
…++ 21)

libc++ 21 (Linux SDK 1.23.0) and current MSVC STL delete the
std::formatter<char*/const char*/std::string, wchar_t> specializations
per C++23 [format.formatter.spec], which collides with WSL's own
char->wide formatter specializations in stringshared.h.

Remove those specializations and widen narrow arguments at the format
boundary instead:

- stringshared.h: drop the char->wide formatter specializations; add a
  WideFormatArg() boundary helper that widens narrow args (char*,
  const char*, char[N], std::string/std::string_view) to wide, identity
  otherwise. On non-Windows it is always identity.
- generateLocalizationHeader.ps1: wrap every Message*() argument with
  WideFormatArg via lifetime-extended locals, so localization call sites
  need no per-site changes.
- ExecutionContext.h: normalize narrow user-error messages to wide via
  ToUserErrorMessage() in the THROW_HR_WITH_USER_ERROR macros.
- Fix the remaining direct std::format(L"...") / reporter sinks that pass
  narrow args (ConsommeNetworking, VersionCommand, ImageProgressCallback,
  ImageTasks, WslClient version macros, tests). Prefer compile-time
  STRING_TO_WIDE_STRING for known-narrow literals.
- packages.config: bump Microsoft.WSL.LinuxSdk to 1.23.0.
Copilot AI review requested due to automatic review settings July 14, 2026 03:27
@benhillis
benhillis force-pushed the libcxx21-formatter-conformant branch from cf8fb35 to 47a953e Compare July 14, 2026 03:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 22 out of 22 changed files in this pull request and generated 3 comments.

Comment on lines +16 to +19
inline std::wstring ToUserErrorMessage(std::string_view message)
{
return wsl::shared::string::MultiByteToWide(std::string{message});
}
Comment on lines +111 to +112
# Widen narrow arguments once into lifetime-extended locals so make_[w]format_args (which
# requires lvalues) can bind to them. LocalizationArg is identity on non-narrow types.
Comment thread packages.config
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
@benhillis benhillis closed this Jul 14, 2026
@benhillis
benhillis deleted the libcxx21-formatter-conformant branch July 14, 2026 16:43
@benhillis

Copy link
Copy Markdown
Member Author

Closing in favor of #41071. The fully-conformant approach (removing the char->wide formatter specializations and widening at every boundary) touches ~22 files, because MSVC and libc++ 21 both delete those specializations, so every direct wide std::format narrow call site must change. The minimal Windows-guarded formatter in #41071 is the better tradeoff.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants