| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent ac823b1 commit de74c34
1 file changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -53,6 +53,8 @@ By default, the **/permissive-** option is not set. When the option is set, the | |||
| 53 | 53 | ||
| 54 | 54 | The **/permissive-** option sets the [/Zc:strictStrings](../../build/reference/zc-conformance.md) and [/Zc:rvalueCast](../../build/reference/zc-conformance.md) options to conforming behavior. They default to non-conforming behavior. You can pass specific **/Zc** options after **/permissive-** on the command line to override this behavior. | |
| 55 | 55 | ||
| 56 | + In versions of the compiler beginning in Visual Studio 2017 Update 3, the **/permissive-** option sets the [/Zc:ternary]() option. The compiler also implements more of the requirements for two-phase name look-up. When the **/permissive-** option is set, the compiler parses function and class template definitions, identifying dependent and non-dependent names used in the templates. In this release, only name dependency analysis is performed. | ||
| 57 | + | ||
| 56 | 58 | Environment-specific extensions and language areas that the standard leaves up to the implementation are not affected by **/permissive-**. For example, the Microsoft-specific `__declspec`, calling convention and structured exception handling keywords, and compiler-specific pragma directives or attributes are not flagged by the compiler in **/permissive-** mode. | |
| 57 | 59 | ||
| 58 | 60 | The **/permissive-** option uses the conformance support in the current compiler version to determine which language constructs are non-conforming. The option does not determine if your code conforms to a specific version of the C++ standard. To enable all implemented compiler support for the latest draft standard, use the [/std:latest](../../build/reference/std-specify-language-standard-version.md) option. To restrict the compiler support to more closely match the C++14 standard, use the [/std:c++14](../../build/reference/std-specify-language-standard-version.md) option, which is the default. | |
@@ -234,6 +236,106 @@ class ATL_NO_VTABLE CFooImpl : public ICustom, | |||
| 234 | 236 | }; | |
| 235 | 237 | ``` | |
| 236 | 238 | ||
| 239 | + #### Ambiguous conditional operator arguments | ||
| 240 | + | ||
| 241 | + In versions of the compiler before Visual Studio 2017 Update 3, the compiler accepted arguments to the conditional operator (or ternary operator) `?:` that are considered ambiguous by the C++17 standard. In **/permissive-** mode, the compiler now issues one or more diagnostics in cases that compiled without diagnostics in earlier versions. | ||
| 242 | + | ||
| 243 | + Commmon errors that may result from this change include: | ||
| 244 | + | ||
| 245 | + - error C2593: 'operator ?' is ambiguous | ||
| 246 | + | ||
| 247 | + - error C2679: binary '?': no operator found which takes a right-hand operand of type 'B' (or there is no acceptable conversion) | ||
| 248 | + | ||
| 249 | + - error C2678: binary '?': no operator found which takes a left-hand operand of type 'A' (or there is no acceptable conversion) | ||
| 250 | + | ||
| 251 | + - error C2446: ':': no conversion from 'B' to 'A' | ||
| 252 | + | ||
| 253 | + A typical code pattern that can cause this issue is when some class C provides both a non-explicit constructor from another type T and a non-explicit conversion operator to type T. In this case, both the conversion of the 2nd argument to the type of the 3rd and the conversion of the 3rd argument to the type of the 2nd are valid conversions, which is ambiguous according to the standard. | ||
| 254 | + | ||
| 255 | + ```cpp | ||
| 256 | + // Example 1: class that provides conversion to and initialization from some type T | ||
| 257 | + struct A | ||
| 258 | + { | ||
| 259 | + A(int); | ||
| 260 | + operator int() const; | ||
| 261 | + }; | ||
| 262 | + | ||
| 263 | + extern bool cond; | ||
| 264 | + | ||
| 265 | + A a(42); | ||
| 266 | + // Accepted when /Zc:ternary or /permissive- is not used: | ||
| 267 | + auto x = cond ? 7 : a; // A: permissive prefers A(7) over (int)a | ||
| 268 | + // Accepted always: | ||
| 269 | + auto y = cond ? 7 : int(a); | ||
| 270 | + auto z = cond ? A(7) : a; | ||
| 271 | + ``` | ||
| 272 | + | ||
| 273 | + There is an important exception to this common pattern when T represents one of the null-terminated string types (for example, `const char *`, `const char16_t *`, and so on) and the actual argument to `?:` is a string literal of corresponding type. C++17 has changed semantics from C++14. As a result, the code in example 2 is accepted under /std:c++14 and rejected under /std:c++17 when **/Zc:ternary** or **/permissive-** is used. | ||
| 274 | + | ||
| 275 | + ```cpp | ||
| 276 | + // Example 2: exception from the above | ||
| 277 | + struct MyString | ||
| 278 | + { | ||
| 279 | + MyString(const char* s = "") noexcept; // from char* | ||
| 280 | + operator const char* () const noexcept; // to char* | ||
| 281 | + }; | ||
| 282 | + | ||
| 283 | + MyString s; | ||
| 284 | + // Accepted when /Zc:ternary or /permissive- is not used: | ||
| 285 | + auto x = cond ? "A" : s; // MyString: permissive prefers MyString("A") over (const char*)s | ||
| 286 | + // Accepted always: | ||
| 287 | + auto y = cond ? "A" : static_cast<const char*>(s); | ||
| 288 | + ``` | ||
| 289 | + | ||
| 290 | + Another case where you may see errors is in conditional optators with one argument of type `void`. This case may be common in ASSERT-like macros. | ||
| 291 | + | ||
| 292 | + ```cpp | ||
| 293 | + // Example 3: void arguments | ||
| 294 | + void myassert(const char* text, const char* file, int line); | ||
| 295 | + // Accepted when /Zc:ternary or /permissive- is not used: | ||
| 296 | + #define ASSERT(ex) (void)((ex) ? 0 : myassert(#ex, __FILE__, __LINE__)) | ||
| 297 | + // Accepted always: | ||
| 298 | + #define ASSERT(ex) (void)((ex) ? void() : myassert(#ex, __FILE__, __LINE__)) | ||
| 299 | + ``` | ||
| 300 | + | ||
| 301 | + You may also see errors in template metaprogramming, where conditional operator result types may change under **/Zc:ternary** and **/permissive-**. One way to resolve this issue is to use `std::remove_reference` on the resulting type. | ||
| 302 | + | ||
| 303 | + ```cpp | ||
| 304 | + // Example 4: different result types | ||
| 305 | + char a = 'A'; | ||
| 306 | + const char b = 'B'; | ||
| 307 | + decltype(auto) x = cond ? a : b; // char without, const char& with /Zc:ternary | ||
| 308 | + const char (&z)[2] = argc > 3 ? "A" : "B"; // const char* without /Zc:ternary | ||
| 309 | + ``` | ||
| 310 | + | ||
| 311 | + #### Name dependency analysis | ||
| 312 | + | ||
| 313 | + When the **/permissive-** option is set in Visual Studio 2017 Update 3, the compiler parses function and class template definitions, identifying dependent and non-dependent names used in templates as required for two-phase look-up. In this release, only name dependency analysis is performed. In particular, non-dependent names that are not declared in the context of a template definition cause a diagnostic message as required by the ISO C++ standards. However, binding of non-dependent names that require argument dependent look up in the definition context is not done. | ||
| 314 | + | ||
| 315 | + ```cpp | ||
| 316 | + // dependency.cpp | ||
| 317 | + // For previous behavior, compile with: cl /W4 dependency.cpp | ||
| 318 | + // For name dependency analysis, compile with: cl /W4 /permissive- dependency.cpp | ||
| 319 | + #include <stdio.h> | ||
| 320 | + | ||
| 321 | + void f(long) { | ||
| 322 | + puts("Standard two-phase!"); | ||
| 323 | + } | ||
| 324 | + | ||
| 325 | + template <typename T> void g(T t) { | ||
| 326 | + f(t); | ||
| 327 | + } | ||
| 328 | + | ||
| 329 | + void f(int) { | ||
| 330 | + puts("Microsoft one-phase!"); | ||
| 331 | + } | ||
| 332 | + | ||
| 333 | + int main() { | ||
| 334 | + g(42); | ||
| 335 | + } | ||
| 336 | + ``` | ||
| 337 | + | ||
| 338 | + | ||
| 237 | 339 | ### To set this compiler option in the Visual Studio development environment | |
| 238 | 340 | ||
| 239 | 341 | 1. Open your project's **Property Pages** dialog box. | |
| Back | FazBrowse Home | New Git URL |
0 commit comments