Skip to content
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

Merged
5 commits merged into from
Dec 8, 2021
Merged

Conversation

lhecker
Copy link
Member

@lhecker lhecker commented Nov 24, 2021

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

@ghost ghost added Area-Build Issues pertaining to the build system, CI, infrastructure, meta Issue-Task It's a feature request, but it doesn't really need a major design. Product-Meta The product is the management of the products. labels Nov 24, 2021
src/host/init.cpp Outdated Show resolved Hide resolved
@lhecker
Copy link
Member Author

lhecker commented Nov 24, 2021

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++. 😄
I've done about a third of the work so far and will send a followup PR for that.
Additionally I'll send a PR to enable /await:strict, however that requires an upgrade of our cppwinrt dependency.

@lhecker lhecker added this to the Engineering Improvements 2021 milestone Nov 24, 2021
@@ -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,
Copy link
Member Author

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.

Copy link
Member

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/host/init.cpp Outdated Show resolved Hide resolved
@@ -118,7 +118,7 @@ class InputRecordConversionTests
dbcsChars,
INPUT_RECORD_COUNT * 2,
nullptr,
false);
FALSE);
Copy link
Member Author

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.

Copy link
Member

Choose a reason for hiding this comment

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

HA ooops

Comment on lines 25 to 28
template<typename T>
T GetIterator()
{
}
Copy link
Member Author

@lhecker lhecker Nov 24, 2021

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.

Copy link
Member

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.

Copy link
Member

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... } {};
Copy link
Member Author

@lhecker lhecker Nov 24, 2021

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
Copy link
Member Author

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.

Copy link
Member

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

Comment on lines +124 to +132
constexpr bool operator==(const Viewport& other) const noexcept
{
return _sr == other._sr;
}

constexpr bool operator!=(const Viewport& other) const noexcept
{
return _sr != other._sr;
}
Copy link
Member Author

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. 😐

Copy link
Member

Choose a reason for hiding this comment

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

how strange.

Copy link
Member

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) };
Copy link
Member Author

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)
Copy link
Member Author

@lhecker lhecker Nov 24, 2021

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.

@lhecker lhecker force-pushed the dev/lhecker/stricter-conformance branch from b58d0fc to 6192935 Compare November 24, 2021 22:28
@lhecker lhecker force-pushed the dev/lhecker/stricter-conformance branch from 6192935 to 1d68188 Compare November 24, 2021 23:28
@lhecker lhecker marked this pull request as ready for review November 24, 2021 23:57
@@ -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,
Copy link
Member

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

@@ -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-.
Copy link
Member

Choose a reason for hiding this comment

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

LOL.

Copy link
Member

Choose a reason for hiding this comment

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

...lol.

Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// 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);
Copy link
Member

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.

Comment on lines +255 to +268
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);
}
}
});

Copy link
Member

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.

Copy link
Member

Choose a reason for hiding this comment

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

wow nice!

Copy link
Member

@miniksa miniksa left a 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.

Copy link
Member

@DHowett DHowett left a 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!

@ghost ghost added the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Dec 2, 2021
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation.
// Copyright (c) Microsoft Corporation.
Copy link
Member

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?

Copy link
Member Author

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.
Copy link
Member

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! :)

Copy link
Member Author

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{};
Copy link
Member

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);
Copy link
Member

Choose a reason for hiding this comment

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

HA ooops

Comment on lines 25 to 28
template<typename T>
T GetIterator()
{
}
Copy link
Member

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.

@@ -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-.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// 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

Comment on lines +255 to +268
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);
}
}
});

Copy link
Member

Choose a reason for hiding this comment

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

wow nice!

Comment on lines +124 to +132
constexpr bool operator==(const Viewport& other) const noexcept
{
return _sr == other._sr;
}

constexpr bool operator!=(const Viewport& other) const noexcept
{
return _sr != other._sr;
}
Copy link
Member

Choose a reason for hiding this comment

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

how strange.

Comment on lines +124 to +132
constexpr bool operator==(const Viewport& other) const noexcept
{
return _sr == other._sr;
}

constexpr bool operator!=(const Viewport& other) const noexcept
{
return _sr != other._sr;
}
Copy link
Member

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)
Copy link
Member

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?

Copy link
Member

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?

Copy link
Member

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

Copy link
Member Author

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.

@ghost ghost removed the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Dec 2, 2021
@DHowett
Copy link
Member

DHowett commented Dec 8, 2021

Let's do it! EIM!

@DHowett DHowett added the AutoMerge Marked for automatic merge by the bot when requirements are met label Dec 8, 2021
@ghost
Copy link

ghost commented Dec 8, 2021

Hello @DHowett!

Because this pull request has the AutoMerge label, I will be glad to assist with helping to merge this pull request once all check-in policies pass.

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 (@msftbot) and give me an instruction to get started! Learn more here.

@ghost ghost merged commit 2b202ce into main Dec 8, 2021
@ghost ghost deleted the dev/lhecker/stricter-conformance branch December 8, 2021 20:00
@ghost
Copy link

ghost commented Feb 3, 2022

🎉Windows Terminal Preview v1.13.10336.0 has been released which incorporates this pull request.:tada:

Handy links:

This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Build Issues pertaining to the build system, CI, infrastructure, meta AutoMerge Marked for automatic merge by the bot when requirements are met Issue-Task It's a feature request, but it doesn't really need a major design. Product-Meta The product is the management of the products.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[MSVC][Build][Permissive-][std:c++latest] Terminal failed to build on MSVC
4 participants