Skip to content

Commit 43b6a0d

Browse files
author
Colin Robertson
committed
Update for 16.5 release
1 parent 0c0b901 commit 43b6a0d

File tree

1 file changed

+196
-5
lines changed

1 file changed

+196
-5
lines changed

docs/overview/cpp-conformance-improvements.md

Lines changed: 196 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: "C++ conformance improvements"
3-
ms.date: "12/04/2019"
3+
ms.date: "03/16/2020"
44
description: "Microsoft C++ in Visual Studio is progressing toward full conformance with the C++20 language standard."
55
ms.technology: "cpp-language"
66
---
@@ -565,7 +565,7 @@ void f(T (&buffer)[Size], int& size_read)
565565
566566
### User-provided specializations of type traits
567567
568-
In compliance with the *meta.rqmts* subclause of the Standard, the MSVC compiler now raises an error when it encounters a user-defined specialization of one of the specified type_traits templates in the `std` namespace. Unless otherwise specified, such specializations result in undefined behavior. The following example has undefined behavior because it violates the rule, and the `static_assert` fails with error **C2338**.
568+
In compliance with the *meta.rqmts* subclause of the Standard, the MSVC compiler now raises an error when it encounters a user-defined specialization of one of the specified `type_traits` templates in the `std` namespace. Unless otherwise specified, such specializations result in undefined behavior. The following example has undefined behavior because it violates the rule, and the `static_assert` fails with error **C2338**.
569569
570570
```cpp
571571
#include <type_traits>
@@ -577,7 +577,7 @@ struct std::is_fundamental<S> : std::true_type {};
577577
static_assert(std::is_fundamental<S>::value, "fail");
578578
```
579579

580-
To avoid the error, define a struct that inherits from the desired type_trait, and specialize that:
580+
To avoid the error, define a struct that inherits from the preferred `type_trait`, and specialize that:
581581

582582
```cpp
583583
#include <type_traits>
@@ -597,7 +597,7 @@ static_assert(my_is_fundamental<S>::value, "fail");
597597
598598
The MSVC compiler now implements the following changes to comparison operators per [P1630R1](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1630r1.html) when the [/std:c++latest](../build/reference/std-specify-language-standard-version.md) option is enabled:
599599
600-
The compiler will no longer rewrite expressions with `operator==` if they involve a return type that is not a **bool**. The following code now produces *error C2088: '!=': illegal for struct*:
600+
The compiler no longer rewrites expressions using `operator==` if they involve a return type that isn't a **bool**. The following code now produces *error C2088: '!=': illegal for struct*:
601601
602602
```cpp
603603
struct U {
@@ -630,7 +630,7 @@ bool neq(const S& lhs, const S& rhs) {
630630
}
631631
```
632632
633-
The compiler will no longer define a defaulted comparison operator if it is a member of a union-like class. The following example now produces *C2120: 'void' illegal with all types*:
633+
The compiler no longer defines a defaulted comparison operator if it's a member of a union-like class. The following example now produces *C2120: 'void' illegal with all types*:
634634
635635
```cpp
636636
#include <compare>
@@ -692,6 +692,197 @@ bool lt(const U& lhs, const U& rhs) {
692692
}
693693
```
694694
695+
## <a name="improvements_165"></a> Conformance improvements in Visual Studio 2019 version 16.5
696+
697+
### Explicit specialization declaration without an initializer is not a definition
698+
699+
Under `/permissive-`, MSVC now enforces a standard rule that explicit specialization declarations without initializers aren't definitions. Previously, the declaration would be considered a definition with a default-initializer. The effect is observable at link time, since a program depending on this behavior may now have unresolved symbols. This example now results in an error:
700+
701+
```cpp
702+
template <typename> struct S {
703+
static int a;
704+
};
705+
706+
// In permissive-, this declaration is not a definition and the program will not link.
707+
template <> int S<char>::a;
708+
709+
int main() {
710+
return S<char>::a;
711+
}
712+
```
713+
714+
```Output
715+
error LNK2019: unresolved external symbol "public: static int S<char>::a" (?a@?$S@D@@2HA) referenced in function _main
716+
at link time.
717+
```
718+
719+
To resolve the issue, add an initializer:
720+
721+
```cpp
722+
template <typename> struct S {
723+
static int a;
724+
};
725+
726+
// Add an initializer for the declaration to be a definition.
727+
template <> int S<char>::a{};
728+
729+
int main() {
730+
return S<char>::a;
731+
}
732+
```
733+
734+
### Preprocessor output preserves newlines
735+
736+
The experimental preprocessor now preserves newlines and whitespace when using `/P` or `/E` with `/experimental:preprocessor`. This change can be disabled by using `/d1experimental:preprocessor:oldWhitespace`.
737+
738+
Given this example source,
739+
740+
```cpp
741+
#define m()
742+
line m(
743+
) line
744+
```
745+
746+
The previous output of `/E` was:
747+
748+
```Output
749+
line line
750+
#line 2
751+
```
752+
753+
The new output of `/E` is now:
754+
755+
```Output
756+
line
757+
line
758+
```
759+
760+
### 'import' and 'module' keywords are context dependent
761+
762+
Per P1857R1, import and module preprocessor directives have additional restrictions on their syntax. This example no longer compiles:
763+
764+
```cpp
765+
import // Invalid
766+
m;
767+
```
768+
769+
It produces the following error message:
770+
771+
```Output
772+
error C2146: syntax error: missing ';' before identifier 'm'
773+
```
774+
775+
To resolve the issue, keep the import on the same line:
776+
777+
```cpp
778+
import m; // OK
779+
```
780+
781+
### Removal of std::weak_equality and std::strong_equality
782+
783+
The merge of P1959R0 requires the compiler to remove behavior and references to the `std::weak_equality` and `std::strong_equality` types.
784+
785+
The code in this example no longer compiles:
786+
787+
```cpp
788+
#include <compare>
789+
790+
struct S {
791+
std::strong_equality operator<=>(const S&) const = default;
792+
};
793+
794+
void f() {
795+
nullptr<=>nullptr;
796+
&f <=> &f;
797+
&S::operator<=> <=> &S::operator<=>;
798+
}
799+
```
800+
801+
The example now leads to these errors:
802+
803+
```Output
804+
error C2039: 'strong_equality': is not a member of 'std'
805+
error C2143: syntax error: missing ';' before '<=>'
806+
error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
807+
error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
808+
error C7546: binary operator '<=>': unsupported operand types 'nullptr' and 'nullptr'
809+
error C7546: binary operator '<=>': unsupported operand types 'void (__cdecl *)(void)' and 'void (__cdecl *)(void)'
810+
error C7546: binary operator '<=>': unsupported operand types 'int (__thiscall S::* )(const S &) const' and 'int (__thiscall S::* )(const S &) const'
811+
```
812+
813+
To resolve the issue, update the `operator<=>` return types:
814+
815+
```cpp
816+
#include <compare>
817+
818+
struct S {
819+
std::strong_ordering operator<=>(const S&) const = default; // prefer 'std::strong_ordering'
820+
};
821+
822+
void f() {
823+
nullptr != nullptr; // use pre-existing builtin operator != or ==.
824+
&f != &f;
825+
&S::operator<=> != &S::operator<=>;
826+
}
827+
```
828+
829+
### TLS Guard changes
830+
831+
Previously, thread-local variables in DLLs weren't correctly initialized before their first use on threads
832+
that existed before the DLL was loaded, other than the thread that loaded the DLL. This defect has now been corrected.
833+
Thread-local variables in such a DLL are initialized immediately before their first use on such threads.
834+
835+
This new behavior of testing for initialization on uses of thread-local variables may be disabled by using the
836+
`/Zc:tlsGuards-` compiler switch. Or, by adding the `[[msvc:no_tls_guard]]` attribute to particular thread local variables.
837+
838+
### Better diagnosis of call to deleted functions
839+
840+
Our compiler was more permissive about calls to deleted functions previously. For example, if the calls happened in the context of a template body, we wouldn't diagnose the call. Additionally, if there were multiple instances of calls to deleted functions, we would only issue one diagnostic. Now we issue a diagnostic for each of them.
841+
842+
One consequence of the new behavior can produce a small breaking change: Code that called a deleted function wouldn't get diagnosed if it was never needed for code generation. Now we diagnose it up front.
843+
844+
This example shows code that now produces an error:
845+
846+
```cpp
847+
struct S {
848+
S() = delete;
849+
S(int) { }
850+
};
851+
852+
struct U {
853+
U() = delete;
854+
U(int i): s{ i } { }
855+
856+
S s{};
857+
};
858+
859+
U u{ 0 };
860+
```
861+
862+
```Output
863+
error C2280: 'S::S(void)': attempting to reference a deleted function
864+
note: see declaration of 'S::S'
865+
note: 'S::S(void)': function was explicitly deleted
866+
```
867+
868+
To resolve the issue, remove calls to deleted functions:
869+
870+
```cpp
871+
struct S {
872+
S() = delete;
873+
S(int) { }
874+
};
875+
876+
struct U {
877+
U() = delete;
878+
U(int i): s{ i } { }
879+
880+
S s; // Do not call the deleted ctor of 'S'.
881+
};
882+
883+
U u{ 0 };
884+
```
885+
695886
## <a name="update_160"></a> Bug fixes and behavior changes in Visual Studio 2019
696887
697888
### Reinterpret_cast in a constexpr function

0 commit comments

Comments
 (0)