-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enable /permissive- and remaining /Zc flags #11816
Conversation
FYI JsonUtils requires extremely far reaching changes to compile with standard conform two phase lookup rules. It almost feels like half the code needs to be rewritten to be compliant with C++. 😄 |
@@ -1216,7 +1216,7 @@ std::wstring Alias::s_MatchAndCopyAlias(const std::wstring& sourceText, | |||
// - LineCount - aliases can contain multiple commands. $T is the command separator | |||
// Return Value: | |||
// - None. It will just maintain the source as the target if we can't match an alias. | |||
void Alias::s_MatchAndCopyAliasLegacy(_In_reads_bytes_(cbSource) PWCHAR pwchSource, | |||
void Alias::s_MatchAndCopyAliasLegacy(_In_reads_bytes_(cbSource) PCWCH pwchSource, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/permissive-
forbids you from passing string literals (const wchar_t*
) in non-const arguments (wchar_t*
).
This is a theme you'll see throughout this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this explains.... years... of bugs
@@ -118,7 +118,7 @@ class InputRecordConversionTests | |||
dbcsChars, | |||
INPUT_RECORD_COUNT * 2, | |||
nullptr, | |||
false); | |||
FALSE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't pass true bools as fake BOOLs anymore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HA ooops
template<typename T> | ||
T GetIterator() | ||
{ | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two phase lookup goes brrrrrrr... with our code ordering.
Just like regular functions, templates also need to be defined before they're used in C++. It's just MSVC that was treating templates as macros for the longest time and didn't do that. A lot of our code depends on this behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ouch. okay this makes sense.
We could also leave them without bodies, correct?
template<typename T>
T GetIterator();
and then provide specializations? Therefore, if we call it with a T that has not been specialized we get a linker error?
Or does this provide a compiler error?
Actually, how does this not provide an error in a compliant parser? There's no return, it should fail before we get to template generation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, this is code you moved. oops.
@@ -97,7 +97,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" | |||
public: | |||
template<typename... Args> | |||
constexpr explicit presorted_static_map(const Args&... args) noexcept : | |||
static_map{ args... } {}; | |||
static_map<K, V, Compare, N, details::presorted_input_t>{ args... } {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These things require template parameters now.
@@ -169,7 +169,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" | |||
// and 5x or more for long strings (128 characters or more). | |||
// See: https:/microsoft/STL/issues/2289 | |||
template<typename T, typename Traits> | |||
bool equals(const std::basic_string_view<T, Traits>& str1, const std::basic_string_view<T, Traits>& str2) noexcept | |||
bool equals(const std::basic_string_view<T, Traits>& lhs, const std::basic_string_view<T, Traits>& rhs) noexcept |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned before, with /permissive-
and true two phase lookup, templates are actually parsed! This means such programming errors can't pass accidentally anymore, because the compiler will actually complain that the code is invalid even if the template isn't used anywhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...wow this template just was never compiled lol
constexpr bool operator==(const Viewport& other) const noexcept | ||
{ | ||
return _sr == other._sr; | ||
} | ||
|
||
constexpr bool operator!=(const Viewport& other) const noexcept | ||
{ | ||
return _sr != other._sr; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't ask me why, but without this change the code doesn't compile. 😐
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how strange.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've always wondered why we did out-of-body inline operators and didn't just put them in the classes
@@ -1368,17 +1368,17 @@ class UiaTextRangeTests | |||
Log::Comment(NoThrowString().Format(L"Forward by %s", toString(textUnit))); | |||
|
|||
// Create an UTR at EndExclusive | |||
const auto utrEnd{ atDocumentEnd ? documentEndExclusive : endExclusive }; | |||
const auto utrEnd{ atDocumentEnd ? documentEndExclusive : static_cast<COORD>(endExclusive) }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/permissive-
implies /Zc:ternary
, which requires both sides of a ternary operator to be of the same type, or implicitly convertible, which this isn't.
|
||
// Flips a random byte value within the buffer. | ||
template<typename _Type> | ||
static _Type* _fz_flipByte(__inout_ecount(rcelms) _Type* p, __inout size_t& rcelms) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These functions are used inside CFuzzLogic
, but depend on CFuzzLogic
themselves.
Since templates aren't macros anymore, we now need to forward declare CFuzzLogic
, then define these and finally define CFuzzLogic
.
b58d0fc
to
6192935
Compare
6192935
to
1d68188
Compare
@@ -1216,7 +1216,7 @@ std::wstring Alias::s_MatchAndCopyAlias(const std::wstring& sourceText, | |||
// - LineCount - aliases can contain multiple commands. $T is the command separator | |||
// Return Value: | |||
// - None. It will just maintain the source as the target if we can't match an alias. | |||
void Alias::s_MatchAndCopyAliasLegacy(_In_reads_bytes_(cbSource) PWCHAR pwchSource, | |||
void Alias::s_MatchAndCopyAliasLegacy(_In_reads_bytes_(cbSource) PCWCH pwchSource, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this explains.... years... of bugs
src/renderer/atlas/AtlasEngine.h
Outdated
@@ -359,7 +359,9 @@ namespace Microsoft::Console::Render | |||
|
|||
bool is_inline() const noexcept | |||
{ | |||
return (__builtin_bit_cast(uintptr_t, allocated) & 1) != 0; | |||
// VSO-1430353: __builtin_bitcast crashes the compiler under /permissive-. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LOL.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...lol.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// VSO-1430353: __builtin_bitcast crashes the compiler under /permissive-. | |
// VSO-1430353: __builtin_bitcast crashes the compiler under /permissive-. (BODGY) |
working around compiler bugs is a BODGE
{ | ||
Status = STATUS_ILLEGAL_FUNCTION; | ||
goto Complete; | ||
Message->SetReplyStatus(STATUS_ILLEGAL_FUNCTION); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that was annoying. Good fix.
const auto cleanup = wil::scope_exit([&]() noexcept { | ||
UnlockConsole(); | ||
|
||
if (!NT_SUCCESS(Status)) | ||
{ | ||
pReceiveMsg->SetReplyStatus(Status); | ||
if (ProcessData != nullptr) | ||
{ | ||
CommandHistory::s_Free(ProcessData); | ||
gci.ProcessHandleList.FreeProcessData(ProcessData); | ||
} | ||
} | ||
}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh it's so beautiful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wow nice!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Love it. Hope we can get closer to doing it in Razzle too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't read the code but I am blocking until we clear or complete the TODOs from the PR body!
src/cascadia/TerminalControl/pch.h
Outdated
@@ -1,4 +1,4 @@ | |||
// Copyright (c) Microsoft Corporation. | |||
// Copyright (c) Microsoft Corporation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be a conflict, right? Adding a BOM is bad, removing one is a conflict?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file currently has a BOM. So this should be a removal. Maybe git ignores it during merge?
I'll merge main into this PR tomorrow just to be sure.
@@ -30,38 +28,35 @@ void InitSideBySide(_Out_writes_(ScratchBufferSize) PWSTR ScratchBuffer, __range | |||
// make references to DLLs in the system that are in the SxS cache (ex. a 3rd party IME is loaded and asks for | |||
// comctl32.dll. The load will fail if SxS wasn't initialized.) This was bug# WIN7:681280. | |||
|
|||
// We look at the first few chars without being careful about a terminal nul, so init them. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have lost the invariant that the scratch buffer is cleared on failure. is that okay?
if you could write a bit about this change, it would be easier to accept! :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I checked the only caller of this function and the name of the argument is correct: It really is just a "scratch(pad) buffer" so that the callee doesn't need to allocate on the heap. It can be left uncleared on return. Additionally the caller calls this function last, right before returning and as such there's no one there to read from it anymore.
{ | ||
NtToWin32PathOffset = 4; | ||
} | ||
|
||
ACTCTXW actctx{}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WAIT a second.
Can ACTCTX not take an NT path here in 2021 on Windows 8.1+?
Can we just use wil::GetModuleFilenameW<std::wstring>
, kill the scratch buffer, and let it allocate? Is that illegal?
@@ -118,7 +118,7 @@ class InputRecordConversionTests | |||
dbcsChars, | |||
INPUT_RECORD_COUNT * 2, | |||
nullptr, | |||
false); | |||
FALSE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HA ooops
template<typename T> | ||
T GetIterator() | ||
{ | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ouch. okay this makes sense.
We could also leave them without bodies, correct?
template<typename T>
T GetIterator();
and then provide specializations? Therefore, if we call it with a T that has not been specialized we get a linker error?
Or does this provide a compiler error?
Actually, how does this not provide an error in a compliant parser? There's no return, it should fail before we get to template generation.
src/renderer/atlas/AtlasEngine.h
Outdated
@@ -359,7 +359,9 @@ namespace Microsoft::Console::Render | |||
|
|||
bool is_inline() const noexcept | |||
{ | |||
return (__builtin_bit_cast(uintptr_t, allocated) & 1) != 0; | |||
// VSO-1430353: __builtin_bitcast crashes the compiler under /permissive-. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// VSO-1430353: __builtin_bitcast crashes the compiler under /permissive-. | |
// VSO-1430353: __builtin_bitcast crashes the compiler under /permissive-. (BODGY) |
working around compiler bugs is a BODGE
const auto cleanup = wil::scope_exit([&]() noexcept { | ||
UnlockConsole(); | ||
|
||
if (!NT_SUCCESS(Status)) | ||
{ | ||
pReceiveMsg->SetReplyStatus(Status); | ||
if (ProcessData != nullptr) | ||
{ | ||
CommandHistory::s_Free(ProcessData); | ||
gci.ProcessHandleList.FreeProcessData(ProcessData); | ||
} | ||
} | ||
}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wow nice!
constexpr bool operator==(const Viewport& other) const noexcept | ||
{ | ||
return _sr == other._sr; | ||
} | ||
|
||
constexpr bool operator!=(const Viewport& other) const noexcept | ||
{ | ||
return _sr != other._sr; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how strange.
constexpr bool operator==(const Viewport& other) const noexcept | ||
{ | ||
return _sr == other._sr; | ||
} | ||
|
||
constexpr bool operator!=(const Viewport& other) const noexcept | ||
{ | ||
return _sr != other._sr; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've always wondered why we did out-of-body inline operators and didn't just put them in the classes
{ | ||
return _CreatePseudoConsole(INVALID_HANDLE_VALUE, size, hInput, hOutput, dwFlags, pPty); | ||
} | ||
|
||
HRESULT AttachPseudoConsole(HPCON hPC, LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList) | ||
static HRESULT AttachPseudoConsole(HPCON hPC, std::wstring& command, PROCESS_INFORMATION* ppi) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
o_O why'd you refactor this out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, why'd you refactor this back in?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, code duplication. Ok, sure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC the problem here was the "you can't pass string literals as mutable wchar_t*
pointers" issue, but fixing it in the existing code was a hassle. So I just refactored the test real quick. As it turns out I was able to remove a lot of code duplication too.
Let's do it! EIM! |
Hello @DHowett! Because this pull request has the p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (
|
🎉 Handy links: |
This commit enables /permissive- for all projects, as well as all other /Zc
flags not enabled by default by /permissive-. Some projects continue to be
built under /Zc:twoPhase- as JsonUtils.h fails to compile otherwise.
PR Checklist