Compartilhar via


Aprimoramentos de conformidade do C++, alterações de comportamento e correções de bugs no Visual Studio 2022

O Microsoft C/C++ no Visual Studio (MSVC) faz aprimoramentos de conformidade e correções de bugs em cada versão. Este artigo lista as melhorias significativas por versão principal e depois pela versão. Para ir diretamente para as alterações de uma versão específica, use os links Neste artigo na parte superior deste artigo.

Este documento lista as alterações no Visual Studio 2022.

Para alterações em versões anteriores do Visual Studio:

Versão Link de melhorias de conformidade
2019 Melhorias de conformidade com o C++ no Visual Studio 2019
2017 Aprimoramentos de conformidade do C++ no Visual Studio 2017
2003-2015 O que há de novo no Visual C++ de 2003 até 2015

Melhorias de conformidade no Visual Studio 2022 versão 17.12

O Visual Studio 2022 versão 17.12 inclui as seguintes melhorias de conformidade, correções de bugs e alterações de comportamento no compilador do Microsoft C/C++.

Para obter um resumo detalhado das alterações feitas na Biblioteca de Modelos Padrão, incluindo alterações de conformidade, correções de bugs e melhorias de desempenho, consulte STL Changelog VS 2022 17.12.

_com_ptr_t::operator bool() agora é explícito

Esta é uma alteração interruptiva de origem/binário.

A conversão implícita para bool instâncias from pode ser surpreendente ou levar a erros do _com_ptr_t compilador. As funções de conversão implícitas são desencorajadas pelas Diretrizes Principais do C++ (C.164) e _com_ptr_t continham conversões implícitas para ambos e bool Interface*. Essas duas conversões implícitas podem levar a ambiguidades.

Para ajudar a resolver isso, a conversão para bool agora é explícita. A conversão para Interface* permanece inalterada.

Uma macro é fornecida para recusar esse novo comportamento e restaurar a conversão implícita anterior. Compile com /D_COM_DISABLE_EXPLICIT_OPERATOR_BOOL para recusar essa alteração. Recomendamos que você modifique o código para não depender de conversões implícitas.

Por exemplo:

#include <comip.h>

template<class Iface>
using _com_ptr = _com_ptr_t<_com_IIID<Iface, &__uuidof(Iface)>>;

int main()
{
   _com_ptr<IUnknown> unk;
   if (unk) // Still valid
   { 
      // ...
   }
   bool b = unk; // Still valid.
   int v = unk; // Previously permitted, now emits C2240: cannot convert from '_com_ptr_t<_com_IIID<IUnknown,& _GUID_00000000_0000_0000_c000_000000000046>>' to 'int'
}

As expressões constantes não estão mais sempre noexcept no modo permissivo

Esta é uma alteração interruptiva de origem/binário.

Uma expressão constante sempre foi noexcept, mesmo que envolvesse uma chamada de função para uma função declarada com uma especificação de exceção potencialmente lançada. Esse texto foi removido no C++17, embora o compilador do Microsoft Visual C++ ainda o suportasse no /permissive modo em todas as versões da linguagem C++.

Esse /permissive comportamento de modo é removido. As expressões constantes não recebem mais um comportamento implícito especial.

O noexcept especificador nas constexpr funções agora é respeitado em todos os modos. Essa alteração é necessária para a implementação correta de resoluções de problemas principais posteriores que dependem do comportamento padrão noexcept .

Por exemplo:

constexpr int f(bool b) noexcept(false)
{ 
    if (b)
    {
        throw 1;
    }
    else
    {
        return 1;
    }
}

void g(bool b)
{
   noexcept(f(b)); // false. No change to behavior
   noexcept(f(true)); // false. No change to behavior
   noexcept(f(false)); // false. Was true in /permissive mode only in previous versions.
}

Melhorias de conformidade no Visual Studio 2022 versão 17.11

O Visual Studio 2022 versão 17.11 inclui as seguintes melhorias de conformidade, correções de bugs e alterações de comportamento no compilador do Microsoft C/C++.

Para obter um resumo detalhado das alterações feitas na Biblioteca de Modelos Padrão, incluindo alterações de conformidade, correções de bugs e melhorias de desempenho, consulte STL Changelog VS 2022 17.11.

Por P3142R0, agora é fácil gerar uma linha em branco com println. Esse recurso está disponível ao compilar com /std:c++latesto . Antes dessa mudança, você escreveu: println(""); Agora você escreve: println();.

  • println(); equivale a println(stdout);
  • println(FILE* stream); equivale a println(stream, "\n");

Implementado range_formatter

Por P2286R8, range_formatter agora está implementado. Esse recurso está disponível ao compilar com /std:c++latesto .

Melhorias de conformidade no Visual Studio 2022 versão 17.10

O Visual Studio 2022 versão 17.10 inclui as seguintes melhorias de conformidade, correções de bugs e alterações de comportamento no compilador do Microsoft C/C++.

Para um resumo detalhado das alterações feitas na Biblioteca de Modelos Standard, incluindo mudanças de conformidade, correções de bug e melhorias de desempenho, consulte Log de Alterações da STL VS 2022 17.10.

Especialização do operador de conversão com tipo de retorno explicitamente especificado

O compilador costumava especializar operadores de conversão incorretamente em alguns casos, o que poderia levar a um tipo de retorno incompatível. Essas especializações inválidas não ocorrem mais. Essa é uma alteração interruptiva do código-fonte.

// Example 1
struct S
{
    template<typename T> operator const T*();
};

void test()
{
    S{}.operator int*(); // this is invalid now
    S{}.operator const int*(); // this is valid
}
// Example 2
// In some cases, the overload resolution result may change
struct S
{
    template <typename T> operator T*(); // overload 1
    template <typename T> operator const T*(); // overload 2
};

void test()
{
    S{}.operator int*(); // this used to call overload 2, now it calls overload 1
}

Adicionado Suporte para #elifdef e #elifndef

Suporte adicionado para WG21 P2334R1 (C++23) e WG14 N2645 (C++23) que introduziram as diretivas de pré-processamento #elifdef e #elifndef. Requer /std:clatest ou /std:c++latest.

Antes:

#ifdef __cplusplus
  #include <atomic>
#elif !defined(__STDC_NO_ATOMICS__)
  #include <stdatomic.h>
#else
  #include <custom_atomics_library.h>
#endif

Depois:

#ifdef __cplusplus
  #include <atomic>
#elifndef __STDC_NO_ATOMICS__
  #include <stdatomic.h>
#else
  #include <custom_atomics_library.h>
#endif

Aplicação de _Alignas em um tipo estruturado em C

Aplica-se à linguagem C (C17 e posteriores). Também adicionado ao Microsoft Visual Studio 17.9

Nas versões do Visual C++ anteriores ao Visual Studio 2022 versão 17.9, se o especificador _Alignas aparecesse adjacente a um tipo estruturado em uma declaração, ele não era aplicado corretamente de acordo com o ISO-C Standard.

// compile with /std:c17
#include <stddef.h>

struct Outer
{
    _Alignas(32) struct Inner { int i; } member1;
    struct Inner member2;
};
static_assert(offsetof(struct Outer, member2)==4, "incorrect alignment");

De acordo com o ISO-C Standard, esse código deve ser compilado sem que static_assert emita um diagnóstico.

A diretiva _Alignas aplica-se somente à variável membro member1. Ela não deve alterar o alinhamento de struct Inner. Entretanto, antes do Visual Studio 17.9.1, o diagnóstico "alinhamento incorreto" era emitido. O compilador alinhava member2 a um deslocamento de 32 bytes dentro do tipo struct Outer.

Essa é uma alteração interruptiva binária, portanto, um aviso agora é emitido quando essa alteração entra em vigor. O aviso C5274 agora é emitido no nível de aviso 1 para o exemplo anterior: warning C5274: behavior change: _Alignas no longer applies to the type 'Inner' (only applies to declared data objects).

Além disso, nas versões anteriores do Visual Studio, quando o especificador _Alignas aparecia adjacente a uma declaração de tipo anônimo, ele era ignorado.

// compile with /std:c17
#include <stddef.h>
struct S
{
    _Alignas(32) struct { int anon_member; };
    int k;
};

static_assert(offsetof(struct S, k)==4, "incorrect offsetof");
static_assert(sizeof(struct S)==32, "incorrect size");

Anteriormente, ambas as declarações static_assert falhavam ao compilar esse código. Agora o código é compilado, mas emite os seguintes avisos de nível 1:

warning C5274: behavior change: _Alignas no longer applies to the type '<unnamed-tag>' (only applies to declared data objects)
warning C5273: behavior change: _Alignas on anonymous type no longer ignored (promoted members will align)

Para obter o comportamento anterior, substitua _Alignas(N) por __declspec(align(N)). Ao contrário de _Alignas, declspec(align) se aplica ao tipo.

Aviso aprimorado C4706

Essa é uma alteração interruptiva do código-fonte. Anteriormente, o compilador não detectava a convenção de encapsulamento de uma atribuição entre parênteses, se a atribuição fosse intencional, para suprimir o aviso C4706 sobre atribuição em uma expressão condicional. Agora, o compilador detecta os parênteses e suprime o aviso.

#pragma warning(error: 4706)

struct S
{
   auto mf()
   {
      if (value = 9)
         return value + 4;
      else
         return value;
   }

   int value = 9;
};

O compilador agora também emite o aviso nos casos em que a função não é referenciada. Anteriormente, como mf é uma função embutida que não é referenciada, o aviso C4706 não era emitido para esse código. Agora o aviso é emitido:

error C4706: assignment used as a condition
note: if an assignment is intended you can enclose it in parentheses, '(e1 = e2)', to silence this warning

Para corrigir esse aviso, use um operador de igualdade, value == 9, se essa for a intenção. Ou, envolva a atribuição entre parênteses, (value = 9), se for essa a intenção. Caso contrário, como a função não é referenciada, remova-a.

Melhorias de conformidade no Visual Studio 2022 versão 17.9

O Visual Studio 2022 versão 17.9 contém as seguintes melhorias de conformidade, correções de erros e alterações de comportamento no compilador do Microsoft C/C++.

Para obter um resumo mais amplo das alterações feitas na Biblioteca de Modelos Standard, consulte STL Changelog VS 2022 17.9.

Aplicação de _Alignas em um tipo estruturado em C

Nas versões do Visual C++ anteriores ao Visual Studio 2022 versão 17.9, quando _Alignas aparecia ao lado de um tipo de estrutura em uma declaração, ele não era aplicado corretamente de acordo com o ISO-C Standard. Por exemplo:

// compile with /std:c17
#include <stddef.h>
struct Outer
{
    _Alignas(32) struct Inner { int i; } member1;
    struct Inner member2;
};
static_assert(offsetof(struct Outer, member2)==4, "incorrect alignment");

De acordo com o ISO-C Standard, esse código deveria ser compilado sem que o static_assert emitisse um diagnóstico. A diretiva _Alignas aplica-se somente à variável membro member1. Ela não deve alterar o alinhamento de struct Inner. No entanto, antes da versão 17.9.1 do Visual Studio, o diagnóstico "alinhamento incorreto" era emitido. O compilador alinhava member2 a um deslocamento de 32 bytes dentro de struct Outer.

Corrigir isso é uma alteração interruptiva binária, portanto, quando essa alteração de comportamento é aplicada, um aviso é emitido. Para o código anterior, o aviso C5274, "_Alignas não se aplica mais ao tipo 'Inner' (aplica-se somente a objetos de dados declarados)" é agora emitido no nível de aviso 1.

Em versões anteriores do Visual Studio, _Alignas era ignorado quando aparecia ao lado de uma declaração de tipo anônimo. Por exemplo:

// compile with /std:c17
#include <stddef.h>
struct S {
    _Alignas(32) struct { int anon_member; };
    int k;
};
static_assert(offsetof(struct S, k)==4, "incorrect offsetof");
static_assert(sizeof(struct S)==32, "incorrect size");

Anteriormente, ambas as declarações static_assert falhavam ao compilar esse código. O código agora é compilado, mas com os seguintes avisos de nível 1:

warning C5274: behavior change: _Alignas no longer applies to the type '<unnamed-tag>' (only applies to declared data objects)
warning C5273: behavior change: _Alignas on anonymous type no longer ignored (promoted members will align)

Se você quiser o comportamento anterior, substitua _Alignas(N) por __declspec(align(N)). Ao contrário de _Alignas, declspec(align) pode ser aplicado a um tipo.

__VA_OPT__ está habilitado como uma extensão em /Zc:preprocessor

__VA_OPT__ foi adicionado ao C++20 e ao C23. Antes de sua adição, não havia uma maneira padrão de omitir uma vírgula em um macro variádico. Para melhorar a compatibilidade com versões anteriores, __VA_OPT__ está habilitado no pré-processador baseado em token /Zc:preprocessor em todas as versões da linguagem.

Por exemplo, isso agora compila sem erros:

#define LOG_WRAPPER(message, ...) WRITE_LOG(__LINE__, message __VA_OPT__(, __VA_ARGS__))

// Failed to build under /std:c11, now succeeds.
LOG_WRAPPER("Log message");
LOG_WRAPPER("Log message with %s", "argument")

Linguagem C23

Para C23, os seguintes recursos estão disponíveis ao usar a alternância do compilador /std:clatest:

typeof
typeof_unqual

O seguinte está disponível para todas as versões da linguagem C:

__typeof__
__typeof_unqual__

Biblioteca Padrão do C++

Características do C++23

  • formattable, range_format, format_kind e set_debug_format() como parte de Intervalos de Formatação P2286R8
  • <mdspan> de acordo com P0009R18 e alterações de redação subsequentes que foram aplicadas ao C++23 Standard.
  • format() ponteiros de acordo com P2510R3.

Melhorias de conformidade no Visual Studio 2022 versão 17.8

O Visual Studio 2022 versão 17.8 contém as seguintes melhorias de conformidade, correções de bug e alterações de comportamento no compilador do Microsoft C/C++.

/FU emite um erro

O compilador C costumava aceitar a opção /FU, embora não tenha suporte para compilação gerenciada há algum tempo. Agora, ele emite um erro. Os projetos que passam essa opção precisam restringi-la somente a projetos C++/CLI.

Biblioteca Padrão C++

Os módulos nomeados C++23 std e std.compat agora estão disponíveis ao compilar com /std:c++20.

Para obter um resumo mais amplo das alterações feitas na Biblioteca Padrão C++, confira STL Changelog VS 2022 17.8.

Melhorias de conformidade no Visual Studio 2022 versão 17.7

O Visual Studio 2022 versão 17.7 contém os seguintes aprimoramentos de conformidade realçados, correções de bug e alterações de comportamento no compilador do Microsoft C/C++.

Adicionado /std:clatest ao compilador C

Essa opção se comporta como a alternância /std:c++latest do compilador C++. A alternância habilita todos os recursos do compilador e da biblioteca padrão atualmente implementados propostos para o próximo rascunho do padrão C, assim como alguns recursos experimentais e em andamento.

Biblioteca Padrão C++

Agora há suporte para a biblioteca <print>. Confira Saída formatada P2093R14.

views::cartesian_product implementado.

Para obter um resumo mais amplo das alterações feitas na Biblioteca de Modelos Padrão, confira STL Changelog VS 2022 17.7.

Conformidade using

Anteriormente, a diretiva using poderia fazer com que os nomes de namespaces usados permanecessem visíveis quando não deveriam. Isso pode fazer com que a pesquisa de nome não qualificada localize um nome em um namespace mesmo quando não houver nenhuma diretiva using ativa.

Aqui estão alguns exemplos do comportamento novo e antigo.
Referências nos seguintes comentários para "(1)" significam a chamada para f<K>(t) no namespace A:

namespace A
{ 
    template<typename K, typename T> 
    auto f2(T t)
    { 
        return f<K>(t); // (1) Unqualified lookup should not find anything
    } 
} 

namespace B
{ 
    template<typename K, typename T> 
    auto f(T t) noexcept
    { // Previous behavior: This function was erroneously found during unqualified lookup at (1)
        return A::f2<K>(t); 
    } 
} 

namespace C
{ 
    template<typename T> 
    struct S {}; 

    template<typename, typename U> 
    U&& f(U&&) noexcept; // New behavior: ADL at (1) correctly finds this function 
} 

namespace D
{ 
    using namespace B; 

    void h()
    { 
        D::f<void>(C::S<int>()); 
    } 
} 

O mesmo problema subjacente pode fazer com que o código compilado anteriormente seja rejeitado:

#include <memory>
namespace Addin {}
namespace Gui
{
    using namespace Addin;
}

namespace Addin
{
    using namespace std;
}

// This previously compiled, but now emits error C2065 for undeclared name 'allocator'.
// This should be declared as 'std::allocator<T*>' because the using directive nominating
// 'std' is not active at this point.
template <class T, class U = allocator<T*>>
class resource_list
{
};

namespace Gui
{
    typedef resource_list<int> intlist;
}

Aprimoramentos de conformidade no Visual Studio 2022 versão 17.6

O Visual Studio 2022 versão 17.6 apresenta os aprimoramentos de conformidade, correções de bug e alterações de comportamento a seguir no compilador do Microsoft C/C++.

Atribuições volatile compostas não foram mais preteridas

C++20 preterido aplicando determinados operadores a tipos qualificados com volatile. Por exemplo, quando o seguinte código é compilado com cl /std:c++20 /Wall test.cpp:

void f(volatile int& expr)
{
   ++expr;
}

O compilador produz test.cpp(3): warning C5214: applying '++' to an operand with a volatile qualified type is deprecated in C++20.

No C++20, os operadores de atribuição composta (operadores do formulário @=) foram preteridos. No C++23, os operadores compostos excluídos no C++20 não são mais preteridos. Por exemplo, no C++23, o código a seguir não produz um aviso, enquanto no C++20:

void f(volatile int& e1, int e2)
{
   e1 += e2;
}

Para obter mais informações sobre essa alteração, confira CWG:2654

Reescrever a igualdade em expressões consiste menos em uma alteração interruptiva (P2468R2)

No C++20, P2468R2 alterou o compilador para aceitar código como:

struct S
{
    bool operator==(const S&);
    bool operator!=(const S&);
};
bool b = S{} != S{};

O compilador aceita esse código, o que significa que o compilador é mais estrito com código como:

struct S
{
  operator bool() const;
  bool operator==(const S&);
};

bool b = S{} == S{};

A versão 17.5 do compilador aceita este programa. A versão 17.6 do compilador o rejeita. Para corrigi-lo, adicione const a operator== para remover a ambiguidade. Ou adicione um correspondente operator!= à definição, conforme mostrado no exemplo a seguir:

struct S
{
  operator bool() const;
  bool operator==(const S&);
  bool operator!=(const S&);
};

bool b = S{} == S{};

As versões 17.5 e 17.6 do compilador do Microsoft C/C++ aceitam o programa anterior e chamadas S::operator== em ambas as versões.

O modelo de programação geral descrito em P2468R2 é que, se há um correspondente operator!= para um tipo, ele normalmente suprime o comportamento de reescrita. Adicionar um correspondente operator!= é a correção sugerida para o código que foi compilado anteriormente no C++17. Para saber mais, confira Modelo de programação.

Aprimoramentos de conformidade no Visual Studio 2022 versão 17.4

O Visual Studio 2022 versão 17.4 apresenta as melhorias de conformidade, correções de bug e alterações de comportamento a seguir no compilador do Microsoft C/C++.

Tipos subjacentes de enum sem escopo sem tipo fixo

Em versões do Visual Studio antes do Visual Studio 2022 versão 17.4, o compilador C++ não determinava corretamente o tipo subjacente de uma enumeração sem escopo sem tipo base fixo. No /Zc:enumTypes, agora implementamos corretamente o comportamento padrão.

O C++ Standard requer que o tipo subjacente de um enum seja grande o suficiente para manter todos os enumeradores nesse enum. Enumeradores suficientemente grandes podem definir o tipo subjacente do enum como unsigned int, long long ou unsigned long long. Anteriormente, esses tipos enum sempre tinham um tipo subjacente de int no compilador da Microsoft, independentemente dos valores do enumerador.

Quando habilitada, a opção /Zc:enumTypes é uma possível alteração de falha de origem e binária. Ela está desativada por padrão e não está habilitada por /permissive- porque a correção pode afetar a compatibilidade binária. Alguns tipos de enumeração mudam de tamanho quando a correção de conformidade está habilitada. Determinados cabeçalhos do SDK do Windows incluem essas definições de enumeração.

Exemplo

enum Unsigned
{
    A = 0xFFFFFFFF // Value 'A' does not fit in 'int'.
};

// Previously, failed this static_assert. Now passes with /Zc:enumTypes.
static_assert(std::is_same_v<std::underlying_type_t<Unsigned>, unsigned int>);

template <typename T>
void f(T x)
{
}

int main()
{
    // Previously called f<int>, now calls f<unsigned int>.
    f(+A);
}

// Previously this enum would have an underlying type of `int`, but Standard C++ requires this to have
// a 64-bit underlying type. Using /Zc:enumTypes changes the size of this enum from 4 to 8, which could
// impact binary compatibility with code compiled with an earlier compiler version or without the switch.
enum Changed
{
    X = -1,
    Y = 0xFFFFFFFF
};

Tipos de enumeradores dentro de uma definição enum sem tipo subjacente fixo

Nas versões do Visual Studio antes do Visual Studio 2022 versão 17.4, o compilador C++ não modelava corretamente os tipos de enumeradores. Ele poderia assumir um tipo incorreto em enumerações sem um tipo subjacente fixo antes da chave de fechamento da enumeração. No /Zc:enumTypes, o compilador agora implementa corretamente o comportamento padrão.

O C++ Standard especifica que, dentro de uma definição de enumeração sem tipo subjacente fixo, os inicializadores determinam os tipos de enumeradores. Ou, para os enumeradores sem inicializador, pelo tipo do enumerador anterior (contabilizando o estouro). Anteriormente, esses enumeradores sempre recebiam o tipo deduzido da enumeração, com um espaço reservado para o tipo subjacente (normalmente int).

Quando habilitada, a opção /Zc:enumTypes é uma possível alteração de falha de origem e binária. Ela está desativada por padrão e não está habilitada por /permissive- porque a correção pode afetar a compatibilidade binária. Alguns tipos de enumeração mudam de tamanho quando a correção de conformidade está habilitada. Determinados cabeçalhos do SDK do Windows incluem essas definições de enumeração.

Exemplo

enum Enum {
    A = 'A',
    B = sizeof(A)
};

static_assert(B == 1); // previously failed, now succeeds under /Zc:enumTypes

Neste exemplo, o enumerador A deve ter o tipo char antes da chave de fechamento da enumeração, então B deve ser inicializado usando sizeof(char). Antes da correção /Zc:enumTypes, A tinha um tipo de enumeração Enum com um tipo subjacente deduzido int e B era inicializado usando sizeof(Enum) ou 4.

Aprimoramentos de conformidade no Visual Studio 2022 versão 17.3

O Visual Studio 2022 versão 17.3 apresenta as melhorias de conformidade, correções de bug e alterações de comportamento a seguir no compilador do Microsoft C/C++.

C: Verificação de compatibilidade aprimorada do modificador entre ponteiros

O compilador C não comparou corretamente os modificadores entre ponteiros, especialmente void*. Esse defeito pode resultar em um diagnóstico inadequado de incompatibilidade entre const int** e void* e compatibilidade entre int* volatile* e void*.

Exemplo

void fn(void* pv) { (pv); }

int main()
{
    int t = 42;
    int* pt = &t;
    int* volatile * i = &pt;
    fn(i);    // Now raises C4090
    const int** j = &pt;
    fn(j);    // No longer raises C4090
}

Aprimoramentos de conformidade no Visual Studio 2022 versão 17.2

O Visual Studio 2022 versão 17.2 apresenta as melhorias de conformidade, correções de bug e alterações de comportamento a seguir no compilador do Microsoft C/C++.

Avisos de caracteres bidirecionais não finalizados

O Visual Studio 2022 versão 17.2 adiciona o aviso de nível 3 C5255 para caracteres bidirecionais Unicode não finalizados em comentários e cadeias de caracteres. O aviso aborda uma preocupação de segurança descrita em Trojan Source: Invisible Vulnerabilities por Nicholas Boucher e Ross Anderson. Para obter mais informações sobre caracteres bidirecionais Unicode, confira Unicode® Standard Annex #9: UNICODE BIDIRECTIONAL ALGORITHM.

O aviso C5255 apenas aborda arquivos que, após a conversão, contêm caracteres bidirecionais Unicode. Esse aviso se aplica aos arquivos UTF-8, UTF-16 e UTF-32, portanto, a codificação de origem adequada deve ser fornecida. Essa alteração é uma alteração interruptiva do código.

Exemplo (antes/depois)

Nas versões do Visual Studio antes do Visual Studio 2022 versão 17.2, um caractere bidirecional não finalizado não produzia um aviso. O Visual Studio 2022 versão 17.2 produz o aviso C5255:

// bidi.cpp
int main() {
    const char *access_level = "user";
    // The following source line contains bidirectional Unicode characters equivalent to:
    //    if ( strcmp(access_level, "user\u202e \u2066// Check if admin \u2069 \u2066") ) {
    // In most editors, it's rendered as:
    //    if ( strcmp(access_level, "user") ) { // Check if admin
    if ( strcmp(access_level, "user‮ ⁦// Check if admin ⁩ ⁦") ) {
        printf("You are an admin.\n");
    }
    return 0;
}

/* build output
bidi.cpp(8): warning C5255: unterminated bidirectional character encountered: 'U+202e'
bidi.cpp(8): warning C5255: unterminated bidirectional character encountered: 'U+2066'
*/

from_chars() float desempate

O Visual Studio 2022 versão 17.2 corrige um bug em <charconv> from_chars() float regras de desempate que produziam resultados incorretos. Esse bug afetava cadeias de caracteres decimais que estavam no ponto médio exato de valores consecutivos float, dentro de um intervalo estreito. (Os menores e maiores valores afetados foram 32768.009765625 e 131071.98828125, respectivamente.) A regra de desempate queria arredondar para "par" e "par" passou a ser "para baixo", mas a implementação arredondou incorretamente "para cima" (double não foi afetada). Para obter mais informações e detalhes de implementação, consulte microsoft/STL#2366.

Essa alteração afeta o comportamento do runtime no intervalo de casos especificado:

Exemplo

// from_chars_float.cpp
#include <cassert>
#include <charconv>
#include <cstdio>
#include <string_view>
#include <system_error>
using namespace std;
int main() {
    const double dbl  = 32768.009765625;
    const auto sv     = "32768.009765625"sv;
    float flt         = 0.0f;
    const auto result = from_chars(sv.data(), sv.data() + sv.size(), flt);
    assert(result.ec == errc{});
    printf("from_chars() returned: %.1000g\n", flt);
    printf("This rounded %s.\n", flt < dbl ? "DOWN" : "UP");
}

Em versões anteriores ao Visual Studio 2022 versão 17.2:

C:\Temp>cl /EHsc /nologo /W4 /std:c++17 from_chars_float.cpp && from_chars_float
from_chars_float.cpp
from_chars() returned: 32768.01171875
This rounded UP.

No Visual Studio 2022 versão 17.2 e posteriores:

C:\Temp>cl /EHsc /nologo /W4 /std:c++17 from_chars_float.cpp && from_chars_float
from_chars_float.cpp
from_chars() returned: 32768.0078125
This rounded DOWN.

/Zc:__STDC__ disponibiliza __STDC__ para C

O padrão do C requer que uma implementação do C em conformidade defina __STDC__ como 1. Devido ao comportamento do UCRT, que não expõe as funções POSIX quando __STDC__ é 1, não é possível definir essa macro para o C por padrão sem introduzir alterações interruptivas nas versões estáveis da linguagem. O Visual Studio 2022 versão 17.2 e posteriores adiciona uma opção de conformidade /Zc:__STDC__ que define essa macro. Não há uma versão negativa da opção. Atualmente, planejamos usar essa opção por padrão para versões futuras do C.

Essa alteração é uma alteração interruptiva do código. Ela se aplica quando o modo C11 ou C17 está habilitado (/std:c11 ou /std:c17) e /Zc:__STDC__ está especificado.

Exemplo

// test__STDC__.c
#include <io.h>
#include <fcntl.h>
#include <stdio.h>

int main() {
#if __STDC__
    int f = _open("file.txt", _O_RDONLY);
    _close(f);
#else
    int f = open("file.txt", O_RDONLY);
    close(f);
#endif
}

/* Command line behavior

C:\Temp>cl /EHsc /W4 /Zc:__STDC__ test__STDC__.c && test__STDC__

*/

Aviso para chaves ausentes

O aviso C5246 relata chaves ausentes durante a inicialização agregada de um subobjeto. Antes do Visual Studio 2022 versão 17.2, o aviso não lidava com o caso de um struct ou union anônimo.

Essa alteração é uma alteração interruptiva do código. Ela se aplica quando o aviso C5246, desativado por padrão, é habilitado.

Exemplo

No Visual Studio 2022 versão 17.2 e posteriores, esse código agora causa um erro:

struct S {
   union {
      float f[4];
      double d[2];
   };
};

void f()
{
   S s = { 1.0f, 2.0f, 3.14f, 4.0f };
}

/* Command line behavior
cl /Wall /c t.cpp

t.cpp(10): warning C5246: 'anonymous struct or union': the initialization of a subobject should be wrapped in braces
*/

Para resolver esse problema, adicione chaves ao inicializador:

void f()
{
   S s = { { 1.0f, 2.0f, 3.14f, 4.0f } };
}

Aprimoramentos de conformidade no Visual Studio 2022 versão 17.1

O Visual Studio 2022 versão 17.1 apresenta as melhorias de conformidade, correções de bug e alterações de comportamento a seguir no compilador do Microsoft C/C++.

Detectar padrão de captura mal formada em expressões lambda não locais

O Padrão do C++ só permite que uma expressão lambda no escopo de bloco tenha um padrão de captura. No Visual Studio 2022 versão 17.1 e posteriores, o compilador detecta quando um padrão de captura não é permitido em uma expressão lambda não local. Ele emite um novo aviso de nível 4, C5253.

Essa alteração é uma alteração interruptiva do código. Ela se aplica a qualquer modo que use o novo processador lambda: /Zc:lambda, /std:c++20 ou /std:c++latest.

Exemplo

No Visual Studio 2022 versão 17.1, esse código agora emite um erro:

#pragma warning(error:5253)

auto incr = [=](int value) { return value + 1; };

// capture_default.cpp(3,14): error C5253: a nonlocal lambda cannot have a capture default
// auto incr = [=](int value) { return value + 1; };
//              ^

Para corrigir esse problema, remova o padrão de captura:

#pragma warning(error:5253)

auto incr = [](int value) { return value + 1; };

O C4028 agora é C4133 para operações de função a ponteiro

Antes do Visual Studio 2022 versão 17.1, o compilador relatava uma mensagem de erro incorreta em determinadas comparações de ponteiro para função no código do C. A mensagem incorreta era relatada quando você comparava dois ponteiros de função que tinham as mesmas contagens de argumentos, mas tipos incompatíveis. Agora, emitimos um aviso diferente que informa da incompatibilidade do ponteiro para a função em vez da incompatibilidade do parâmetro da função.

Essa alteração é uma alteração interruptiva do código. Aplica-se quando o código é compilado como C.

Exemplo

int f1(int); 
int f2(char*); 
int main(void) 
{ 
    return (f1 == f2); 
}
// Old warning:
// C4028: formal parameter 1 different from declaration
// New warning:
// C4113: 'int (__cdecl *)(char *)' differs in parameter lists from 'int (__cdecl *)(int)'

Erro em um static_assert não dependente

No Visual Studio 2022, versão 17.1 e posteriores, se a expressão associada a um static_assert não for uma expressão dependente, o compilador avalia a expressão quando ela é analisada. Se a expressão for avaliada como false, o compilador emitirá um erro. Anteriormente, se a static_assert estivesse dentro do corpo de um modelo de função (ou dentro do corpo de uma função membro de um modelo de classe), o compilador não executaria essa análise.

Essa alteração é uma alteração interruptiva do código. Ela se aplica a qualquer modo que implique /permissive- ou /Zc:static_assert. Essa alteração no comportamento pode ser desabilitada usando a opção do compilador /Zc:static_assert-.

Exemplo

No Visual Studio 2022 versão 17.1 e posteriores, esse código agora causa um erro:

template<typename T>
void f()
{
   static_assert(false, "BOOM!");
}

Para corrigir esse problema, torne a expressão dependente. Por exemplo:

template<typename>
constexpr bool dependent_false = false;

template<typename T>
void f()
{
   static_assert(dependent_false<T>, "BOOM!");
}

Com essa alteração, o compilador só emitirá um erro se o modelo de função f for instanciado.

Aprimoramentos de conformidade no Visual Studio 2022 versão 17.0

O Visual Studio 2022 versão 17.0 apresenta as melhorias de conformidade, correções de bug e alterações de comportamento a seguir no compilador do Microsoft C/C++.

Aviso na largura do campo de bits para o tipo enumeração

Quando você declara uma instância de um tipo de enumeração como um campo de bits, a largura do campo de bits deve acomodar todos os valores possíveis da enumeração. Caso contrário, o compilador emitirá uma mensagem de diagnóstico. Considere este exemplo: Considere:

enum class E : unsigned { Zero, One, Two };

struct S {
  E e : 1;
};

Um programador pode esperar que o membro da classe S::e possa conter qualquer um dos valores explicitamente nomeados enum. Dado o número de elementos de enumeração, isso não é possível. O campo de bits não pode cobrir o intervalo de valores fornecidos explicitamente de E (conceitualmente, o domínio de E). Para resolver a questão de que a largura do campo de bits não é grande o suficiente para o domínio da enumeração, um novo aviso (desativado por padrão) foi adicionado ao MSVC:

t.cpp(4,5): warning C5249: 'S::e' of type 'E' has named enumerators with values that cannot be represented in the given bit field width of '1'.
  E e : 1;
    ^
t.cpp(1,38): note: see enumerator 'E::Two' with value '2'
enum class E : unsigned { Zero, One, Two };
                                     ^

Esse comportamento do compilador é uma alteração interruptiva de código e binário que afeta os modos /std e /permissive.

Erro na comparação ordenada de ponteiro em relação a nullptr ou 0

O Padrão do C++ inadvertidamente permitia uma comparação de ponteiro ordenada em relação a nullptr ou 0. Por exemplo:

bool f(int *p)
{
   return p >= 0;
}

O trabalho N3478 do WG21 removeu essa omissão. Essa alteração é implementada no MSVC. Quando o exemplo é compilado usando /permissive- (e /diagnostics:caret), ele emite o seguinte erro:

t.cpp(3,14): error C7664: '>=': ordered comparison of pointer and integer zero ('int *' and 'int')
    return p >= 0;
             ^

Esse comportamento do compilador é uma alteração de falha de código e binária que afeta o código compilado usando /permissive- em todos os modos /std.

Confira também

Conformidade com a linguagem do Microsoft C/C++