Sdílet prostřednictvím


Vylepšení shody jazyka C++, změny chování a opravy chyb v sadě Visual Studio 2022

Microsoft C/C++ ve Visual Studiu (MSVC) vylepšuje shodu a opravuje chyby v každé verzi. Tento článek uvádí významná vylepšení v hlavní verzi a potom podle verze. Pokud chcete přejít přímo na změny konkrétní verze, použijte odkazy v tomto článku v horní části tohoto článku.

Tento dokument uvádí změny ve Visual Studio 2022.

Změny v dřívějších verzích sady Visual Studio:

Verze Vylepšení shody - odkaz
2019 Vylepšení shody jazyka C++ v sadě Visual Studio 2019
2017 Vylepšení souladu C++ ve Visual Studio 2017
2003-2015 Novinky Visual C++ 2003–2015

Vylepšení souladu v aplikaci Visual Studio 2022 verze 17.14

Visual Studio 2022 verze 17.14 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.

Vylepšení shody

  • Posílení zabezpečení standardní knihovny (P3471R4) změní některé instance nedefinovaného chování ve standardní knihovně na volání __fastfail. Ve výchozím nastavení je vypnuto. Definujte _MSVC_STL_HARDENING=1 pro celý projekt, aby se povolil.

Vylepšené chování

  • Implementovali jsme "destruktorové náhrobky" pro zmírnění chyb použití bez použití. Ve výchozím nastavení je vypnuto. Definujte _MSVC_STL_DESTRUCTOR_TOMBSTONES=1 pro celý projekt, aby se povolil.

Opravy chyb

  • Opravili jsme chyby kompilátoru errantu při použití <format> v projektu CUDA.

  • Opravili jsme problém kompilátoru, který způsoboval, že adresa místní proměnné mohla během constexpr vyhodnocení uniknout. Příklad:

    const unsigned & func() 
    {
      const int x = 0;
      constexpr const unsigned & r1 = x; // Previously accepted, now an error
      return r1;
    }
    
    auto r = func();  // Previously, the local address leaked
    

    Příklad č. 2

    #include <initializer_list>
    
    void test()
    {
        constexpr std::initializer_list<int> xs { 1, 2, 3 };        // Previously accepted, now an error
    
        static constexpr std::initializer_list<int> ys { 1, 2, 3 }; // Correct usage - note use of static
    }
    
  • Kód zkompilovaný s /permissive- již nepřijímá kombinaci friend a static v deklaraci. Oprava je obvykle odstranění static z deklarace. Příklad:

    struct S
    {
        friend static void f(); // Previously accepted, now emits error C2440: 'static' cannot be used with 'friend'
    };
    
  • Vazba odkazů na typy kvalifikované nestálostí byla opravena při odkazování na základní nebo odvozenou třídu. Příklad:

    struct A {};
    struct B : public A {};
    
    void f(A&);                 // 1
    void f(const volatile A&);  // 2
    
    f(B{}); // Previously called 2. This is ill-formed under /permissive- or /Zc:referenceBinding. Chooses 1 if relaxed reference binding rules are enabled.
    

Podrobný přehled změn provedených ve standardní knihovně šablon, včetně změn shody, oprav chyb a vylepšení výkonu, najdete v tématu STL Changelog VS 2022 17.14.

Vylepšení kompatibility v sadě Visual Studio 2022 verze 17.13

Visual Studio 2022 verze 17.13 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.

Podrobný přehled změn provedených ve standardní knihovně šablon, včetně změn shody, oprav chyb a vylepšení výkonu, najdete v tématu protokol změn STL VS 2022 17.13.

Vyhledávání závislé na argumentech (ADL)

Jazykové konstrukce, jako je "range-for" a strukturované vazby, mají speciální pravidla pro vyhledávání závislá na argumentech pro určité identifikátory, jako jsou begin, endnebo get. Dříve toto vyhledávání zahrnovalo kandidáty z std oboru názvů, i když obor názvů std není součástí běžné sady přidružených oborů názvů pro vyhledávání závislé na argumentech.

Programy, které zavedly deklarace pro std pro tyto konstrukty již nejsou kompilovány. Místo toho by deklarace měly být v normálním přidruženém oboru názvů pro příslušné typy (pravděpodobně včetně globálního oboru názvů).

template <typename T>
struct Foo {};

namespace std
{
    // To correct the program, move these declarations from std to the global namespace
    template <typename T>
    T* begin(Foo<T>& f);
    template <typename T>
    T* end(Foo<T>& f);
}

void f(Foo<int> foo)
{
   for (auto x : foo) // Previously compiled. Now emits error C3312: no callable 'begin' function found for type 'Foo<int>'
   {
      ...
   }
}

Nelze upravit makra vyhrazená pro implementaci

Dříve kompilátor umožňoval změnu nebo zrušení definice některých maker poskytovaných implementací, jako je _MSC_EXTENSIONS. Změna definice určitých maker může mít za následek nedefinované chování.

Při pokusu o změnu nebo zrušení definice některých rezervovaných makro názvů se nyní zobrazí upozornění úrovně 1 C5308. V režimu /permissive- se toto upozornění považuje za chybu.

#undef _MSC_EXTENSIONS // Warning C5308: Modifying reserved macro name `_MSC_EXTENSIONS` may cause undefined behavior

Vylepšení souladu v aplikaci Visual Studio 2022 verze 17.12

Visual Studio 2022 verze 17.12 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.

Podrobný přehled změn provedených ve standardní knihovně šablon, včetně změn shody, oprav chyb a vylepšení výkonu, najdete v tématu STL Changelog VS 2022 17.12.

_com_ptr_t::operator bool() je teď explicitní

Jedná se o zdrojovou nebo binární změnu způsobující nekompatibilitu.

Implicitní převod do bool z _com_ptr_t instancí může být překvapivý nebo může vést k chybám kompilátoru. C.164: Vyhněte se implicitním převodním operátorům v pokynech pro C++ Core Guidelines, které nedoporučují implicitní převodní funkce. A _com_ptr_t obsahoval implicitní převody na oba bool a Interface*. Tyto dva implicitní převody můžou vést k nejednoznačnostem.

Převod na bool je nyní explicitní. Převod na Interface* se nezmění.

K dispozici je makro pro odhlášení od tohoto nového chování a obnovení předchozího implicitního převodu. Skompilujte s /D_COM_DISABLE_EXPLICIT_OPERATOR_BOOL pro zrušení této změny. Doporučujeme upravit kód tak, aby nespoléhal na implicitní převody.

Příklad:

#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'
}

Výrazy konstant už nejsou vždy noexcept v povoleném režimu.

Jedná se o zdrojovou nebo binární změnu způsobující nekompatibilitu.

Konstantní výraz byl vždy noexcept, i když zahrnoval volání funkce deklarované s potenciálně vyvolanou specifikací výjimky. Toto znění bylo odebráno v jazyce C++17, ačkoli kompilátor Microsoft Visual C++ ho stále podporuje v /permissive režimu ve všech jazykových verzích jazyka C++.

Chování režimu /permissive bylo odebráno. Konstantní výrazy už nemají zvláštní implicitní chování.

Specifikátor noexceptconstexpr funkcí je nyní respektován ve všech režimech. Tato změna se vyžaduje pro správnou implementaci pozdějších základních řešení problémů, která závisí na standardním noexcept chování.

Příklad:

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

Zlepšení shody v sadě Visual Studio 2022 verze 17.11

Visual Studio 2022 verze 17.11 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.

Podrobný přehled změn provedených ve standardní knihovně šablon, včetně změn shody, oprav chyb a vylepšení výkonu, najdete v tématu STL Changelog VS 2022 17.11.

Na P3142R0 je teď snadné vygenerovat prázdný řádek s println. Tato funkce je k dispozici při kompilaci pomocí /std:c++latest. Před touto změnou jste napsali: println(""); Nyní píšete: println();.

  • println(); je ekvivalentní println(stdout);
  • println(FILE* stream); je ekvivalentní println(stream, "\n");

Implementováno range_formatter

Podle P2286R8 je nyní implementováno. Tato funkce je k dispozici při kompilaci pomocí /std:c++latest.

Vylepšení shody v Visual Studio 2022 verze 17.10

Visual Studio 2022 verze 17.10 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.

Podrobný přehled změn provedených ve standardní knihovně šablon, včetně změn shody, oprav chyb a vylepšení výkonu, najdete v tématu STL Changelog VS 2022 17.10.

Specializace operátoru převodu s explicitně zadaným návratovým typem

Kompilátor někdy nesprávně specializoval převodní operátory, což mohlo vést k neshodě návratového typu. K těmto neplatným specializacem už nedojde. Jedná se o změnu způsobující chybu zdrojového kódu.

// 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
}

Přidání podpory pro #elifdef a #elifndef

Byla přidána podpora pro WG21 P2334R1 (C++23) a WG14 N2645 (C++23), která zavedla direktivy preprocesoru #elifdef a #elifndef preprocesoru. Vyžaduje /std:clatest nebo /std:c++latest.

Před:

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

Po:

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

Použití strukturovaného _Alignas typu v jazyce C

Platí pro jazyk C (C17 a novější). Přidáno také do sady Microsoft Visual Studio 17.9

Ve verzích Visual C++ před Visual Studio 2022 verzí 17.9, pokud se specifikátor _Alignas objevil vedle strukturovaného typu v deklaraci, nebyl správně použit podle standardu ISO-C.

// 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");

Podle standardu ISO-C by se měl tento kód zkompilovat bez vyvolání diagnostiky.

Direktiva _Alignas se vztahuje pouze na členské proměnné member1. Nesmí měnit zarovnání struct Inner. Před verzí Visual Studio 17.9.1 však byla vygenerována diagnostika nesprávného zarovnání. Kompilátor zarovnal member2 na posun o 32 bajtů v typu struct Outer.

Jedná se o binární zásadní změnu, takže se teď vygeneruje upozornění, když se tato změna projeví. Upozornění C5274 je nyní generováno na úrovni upozornění 1 pro předchozí příklad: warning C5274: behavior change: _Alignas no longer applies to the type 'Inner' (only applies to declared data objects).

V předchozích verzích sady Visual Studio byl také ignorován specifikátor, který se objevil vedle deklarace anonymního typu.

// 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");

Dříve se oba static_assert příkazy při kompilaci tohoto kódu nezdařily. Kód se teď zkompiluje, ale vygeneruje následující upozornění na úroveň 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)

Chcete-li získat předchozí chování, nahraďte _Alignas(N) .__declspec(align(N)) Na rozdíl od _Alignas se declspec(align) vztahuje na typ.

Vylepšené upozornění C4706

Jedná se o změnu způsobující chybu zdrojového kódu. Dříve kompilátor nedetekoval konvenci obalení přiřazení do závorek, pokud bylo přiřazení zamýšleno, aby potlačil upozornění C4706 týkající se přiřazení v rámci podmíněného výrazu. Kompilátor teď rozpozná závorky a potlačí upozornění.

#pragma warning(error: 4706)

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

   int value = 9;
};

Kompilátor teď také vygeneruje upozornění v případech, kdy se na funkci neodkazuje. Dříve, protože mf je vložená funkce, na kterou se neodkazuje, upozornění C4706 se pro tento kód nevygenerovalo. Nyní se vygeneruje upozornění:

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

Chcete-li toto upozornění opravit, pokud to bylo zamýšleno, použijte operátor rovnosti value == 9. Nebo zabalte přiřazení do závorek, (value = 9)pokud má přiřazení být provedeno. Jelikož funkce není odkazovaná, odeberte ji.

Vylepšení shody ve Visual Studio 2022 verze 17.9

Visual Studio 2022 verze 17.9 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.

Širší souhrn změn provedených v knihovně standardní šablony najdete v tématu STL Changelog VS 2022 17.9.

Použití strukturovaného _Alignas typu v jazyce C

Ve verzích Visual C++ před sadou Visual Studio 2022 verze 17.9, když se _Alignas objevilo vedle typu struktury v deklaraci, nebylo správně aplikováno podle standardu ISO-C. Příklad:

// 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");

Podle standardu ISO-C by se měl tento kód zkompilovat, aniž by generoval diagnostiku pomocí static_assert. Direktiva _Alignas se vztahuje pouze na členské proměnné member1. Nesmí měnit zarovnání struct Inner. Před verzí 17.9.1 sady Visual Studio se však generovala chybová hláška „incorrect alignment“. Kompilátor zarovnal member2 na offset 32 bajtů uvnitř struct Outer.

Oprava této chyby je binární zásadní změnou, takže při použití této změny chování je vydáno varování. U předchozího kódu se varování C5274, "_Alignas již neplatí pro typ 'Inner' (platí pouze pro deklarované datové objekty)", nyní generuje na úrovni varování 1.

V předchozích verzích sady Visual Studio byla ignorována, _Alignas když se zobrazila vedle deklarace anonymního typu. Příklad:

// 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");

Dříve se oba static_assert příkazy při kompilaci tohoto kódu nezdařily. Kód se teď zkompiluje, ale s následujícími upozorněními úrovně 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)

Pokud chcete dřívější chování, nahraďte ho _Alignas(N).__declspec(align(N)) Na rozdíl od _Alignas lze declspec(align) aplikovat na typ.

__VA_OPT__ je povolen jako rozšíření v části /Zc:preprocessor

__VA_OPT__ byl přidán do C++20 a C23. Před jeho přidáním neexistoval standardní způsob, jak vynechat čárku ve variadickém makru. Aby byla zajištěna lepší zpětná kompatibilita, __VA_OPT__ je povolena pod preprocesorem /Zc:preprocessor založeným na tokenech ve všech jazykových verzích.

Teď se například zkompiluje bez chyby:

#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")

Jazyk C23

Pro C23 jsou při použití přepínače kompilátoru /std:clatest k dispozici následující možnosti:

typeof
typeof_unqual

Pro všechny jazykové verze jazyka C jsou k dispozici následující:

__typeof__
__typeof_unqual__

Standardní knihovna C++

Funkce C++23

Vylepšení shody v Visual Studio 2022 verze 17.8

Visual Studio 2022 verze 17.8 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.

/FU vyvolá chybu

Kompilátor jazyka /FU C tuto možnost přijal, i když nějakou dobu nepodporuje spravovanou kompilaci. Teď se zobrazí chyba. Projekty, které splňují tuto možnost, musí ji omezit na projekty C++/CLI.

Standardní knihovna C++

Pojmenované moduly std C++23 a std.compat jsou nyní k dispozici při kompilaci pomocí /std:c++20.

Širší souhrn změn provedených ve standardní knihovně C++ najdete v tématu STL Changelog VS 2022 17.8.

Vylepšení souladu v Visual Studio 2022 verze 17.7

Visual Studio 2022 verze 17.7 obsahuje následující zvýrazněná vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.

Přidáno /std:clatest do kompilátoru jazyka C

Tento přepínač se chová jako /std:c++latest přepínač kompilátoru jazyka C++. Přepínač umožňuje všechny aktuálně implementované funkce kompilátoru a standardní knihovny navržené pro další verzi standardu jazyka C a také některé probíhající a experimentální funkce.

Standardní knihovna C++

Knihovna <print> je nyní podporovaná. Viz P2093R14 formátovaný výstup.

Implementováno views::cartesian_product.

Širší souhrn změn provedených v knihovně standardních šablon najdete v tématu STL Changelog VS 2022 17.7.

using konformita

Dříve mohla direktiva using způsobit, že názvy z použitých oborů názvů zůstávaly viditelné i tehdy, kdy by neměly. Může to způsobit, že vyhledávání nekvalifikovaných názvů najde název v oboru názvů, i když není žádná směrnice using aktivní.

Tady je několik příkladů nového a starého chování.
Odkazy v následujících komentářích na "(1)" znamenají volání funkce f<K>(t) v jmenném prostoru 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>()); 
    } 
} 

Stejný základní problém může způsobit odmítnutí kódu, který byl dříve zkompilován:

#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;
}

Vylepšení kompatibility pro Visual Studio 2022 verzi 17.6

Visual Studio 2022 verze 17.6 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.

Složená volatile přiřazení už nejsou zastaralá

C++20 označilo použití určitých operátorů pro typy kvalifikované pomocí volatile za zastaralé. Například při kompilaci následujícího kódu s cl /std:c++20 /Wall test.cpp:

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

Kompilátor vytvoří test.cpp(3): warning C5214: applying '++' to an operand with a volatile qualified type is deprecated in C++20.

V jazyce C++20 byly operátory složeného přiřazení (operátory formuláře @=) zastaralé. V jazyce C++23 už nejsou složené operátory označené jako zastaralé v C++20 považované za zastaralé. Například v jazyce C++23 následující kód negeneruje upozornění, zatímco v jazyce C++20:

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

Další informace o této změně naleznete v tématu CWG:2654

Přepisování rovnosti ve výrazech je méně zásadní změnou (P2468R2)

V C++20 P2468R2 změnil kompilátor tak, aby přijímal kód, například:

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

Kompilátor přijímá tento kód, což znamená, že kompilátor je přísnější s kódem, například:

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

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

Tento program přijímá verze 17.5 kompilátoru. Verze 17.6 kompilátoru ji odmítne. Chcete-li to opravit, přidejte const do operator== a odstraňte tak nejednoznačnost. Nebo přidejte odpovídající operator!= k definici, jak je znázorněno v následujícím příkladu.

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

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

Kompilátory Microsoft C/C++ ve verzích 17.5 a 17.6 přijímají předchozí program a provedou volání na S::operator== v obou verzích.

Obecný programovací model popsaný v P2468R2 spočívá v tom, že pokud existuje odpovídající operator!= pro typ, obvykle potlačí přepisovací chování. Přidání odpovídajícího operator!= je navrhovanou opravou pro kód, který byl dříve kompatibilní s C++17. Další informace naleznete v tématu Programovací model.

Vylepšení souladu v sadě Visual Studio 2022 verze 17.4

Visual Studio 2022 verze 17.4 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.

Základní typy nesvázané bez pevného typu enum

Ve verzích sady Visual Studio před sadou Visual Studio 2022 verze 17.4 kompilátor jazyka C++ neurčil správně základní typ neskopovaného výčtu bez pevného základního typu. V části /Zc:enumTypes, nyní správně implementujeme standardní chování.

Standard jazyka C++ vyžaduje, aby byl základní typ dostatečně enum velký, aby pojmul všechny enumerátory v daném enum. Dostatečně velcí enumerátory mohou nastavit základní typ enum na unsigned int, long long nebo unsigned long long. Dříve tyto enum typy měly vždy základní typ int v kompilátoru Microsoftu bez ohledu na hodnoty enumerátoru.

Pokud je možnost /Zc:enumTypes povolena, může dojít k potenciální změně, která poruší funkčnost, jak na úrovni zdrojového kódu, tak i binární úrovni. Ve výchozím nastavení je vypnutý, a není povolený pomocí /permissive-, protože oprava může ovlivnit binární kompatibilitu. Některé typy výčtů mění velikost, když je povolena odpovídající oprava. Některé hlavičky sady Windows SDK zahrnují takové definice výčtu.

Příklad

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
};

Typy výčtů v definici enum bez pevného podkladového typu

Ve verzích sady Visual Studio před sadou Visual Studio 2022 verze 17.4 kompilátor jazyka C++ nemodeloval správně typy výčtů. Před ukončovací závorkou výčtu by se mohl předpokládat nesprávný typ v rámci výčtů bez pevného základního typu. V části /Zc:enumTypes, kompilátor nyní správně implementuje standardní chování.

Standard jazyka C++ určuje, že v rámci definice výčtu bez pevně stanoveného základního typu inicializátory určují typy výčtových konstant. Nebo pro enumerátory bez inicializátoru podle typu předchozího enumerátoru (účetující přetečení). Dříve byly těmto enumerátorům vždy přiřazovány odvozené typy výčtu se zástupným symbolem pro základní datový typ (obvykle int).

Pokud je možnost /Zc:enumTypes povolena, může dojít k potenciální změně, která poruší funkčnost, jak na úrovni zdrojového kódu, tak i binární úrovni. Ve výchozím nastavení je vypnutý, a není povolený pomocí /permissive-, protože oprava může ovlivnit binární kompatibilitu. Některé typy výčtů mění velikost, když je povolena odpovídající oprava. Některé hlavičky sady Windows SDK zahrnují takové definice výčtu.

Příklad

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

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

V tomto příkladu by enumerátor A měl mít typ char před závorkou výčtu, takže B by měl být inicializován pomocí sizeof(char). Před opravou měl /Zc:enumTypesA typ Enum výčtu s odvozeným základním typem int, a B byl inicializován pomocí sizeof(Enum) nebo 4.

Vylepšení souladu v sadě Visual Studio 2022 verze 17.3

Visual Studio 2022 verze 17.3 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.

C: Vylepšená kontrola kompatibility modifikátorů mezi ukazateli

Kompilátor jazyka C správně nerovnal modifikátory mezi ukazateli, zejména void*. Tato chyba by mohla vést k nesprávné diagnostice nekompatibility mezi const int** a void* a kompatibility mezi int* volatile* a void*.

Příklad

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
}

Vylepšení kompatibility v sadě Visual Studio 2022 verze 17.2

Visual Studio 2022 verze 17.2 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.

Upozornění na neukončené obousměrné znaky

Visual Studio 2022 verze 17.2 přidává upozornění na úroveň 3 C5255 pro neukončené znaky Unicode obousměrné v komentářích a řetězcích. Toto upozornění se zabývá bezpečnostním problémem popsaným v Trojan Source: Neviditelné zranitelnosti Nicholasem Boucherem a Rossem Andersonem. Další informace o obousměrnýchch kódech Unicode naleznete v článku Standardní příloha unicode® č. 9: UNICODE BIDIRECTIONAL ALGORITHM.

Upozornění C5255 řeší pouze soubory, které po převodu obsahují obousměrné znaky Unicode. Toto upozornění platí pro soubory UTF-8, UTF-16 a UTF-32, takže musí být zadáno správné kódování zdroje. Tato změna narušuje kompatibilitu se zdrojem.

Příklad (před/po)

Ve verzích Visual Studio před Visual Studio 2022 verze 17.2 neuzavřený obousměrný znak nevyvolal varování. Visual Studio 2022 verze 17.2 generuje upozornění 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 rozhodující bod

Visual Studio 2022 verze 17.2 opravuje chybu v <charconv>from_chars()float pravidlech tiebreakeru, která vytvořila nesprávné výsledky. Tato chyba ovlivnila desetinné řetězce, které byly na přesné střední bodě po sobě jdoucích float hodnot v úzkém rozsahu. cs-CZ: (Nejmenší a největší ovlivněné hodnoty byly 32768.009765625 a 131071.98828125.) Pravidlo pro rozlišení při rovnosti chtělo zaokrouhlit na "sudé", a "sudé" v tomto případě znamenalo "dolů", ale implementace nesprávně zaokrouhlila "nahoru" (hodnota double zůstala neovlivněná). Další informace a podrobnosti o implementaci najdete na microsoft/STL#2366.

Tato změna má vliv na chování modulu runtime v zadaném rozsahu případů:

Příklad

// 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");
}

Ve verzích před Visual Studio 2022 verze 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.

Ve Visual Studiu 2022 verze 17.2 a novější:

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__ zpřístupní __STDC__ pro jazyk C

Standard jazyka C vyžaduje, aby odpovídající implementace jazyka C byla definována __STDC__ jako 1. Vzhledem k chování UCRT, který nezpřístupňuje funkce POSIX, pokud __STDC__ je 1, není možné definovat toto makro pro jazyk C ve výchozím nastavení bez zavedení zásadních změn ve stabilních jazykových verzích. Visual Studio 2022 verze 17.2 a novější přidávají možnost shody /Zc:__STDC__, která definuje toto makro. Neexistuje žádná záporná verze možnosti. V současné době plánujeme tuto možnost používat ve výchozím nastavení pro budoucí verze jazyka C.

Tato změna narušuje kompatibilitu se zdrojem. Platí, pokud je povolen režim C11 nebo C17 (/std:c11 nebo /std:c17) a /Zc:__STDC__ je zadán.

Příklad

// 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__

*/

Upozornění na chybějící složené závorky

Upozornění C5246 oznamuje chybějící složené závorky při agregované inicializaci podobjektu. Před verzí 17.2 sady Visual Studio 2022 neřešilo upozornění případ anonymního struct nebo union.

Tato změna narušuje kompatibilitu se zdrojem. Platí, když je povolené upozornění C5246, které je ve výchozím nastavení vypnuté.

Příklad

V sadě Visual Studio 2022 verze 17.2 a novější teď tento kód způsobí chybu:

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
*/

Pokud chcete tento problém vyřešit, přidejte do inicializátoru složené závorky:

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

Vylepšení souladu v sadě Visual Studio 2022 verze 17.1

Visual Studio 2022 verze 17.1 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.

Detekce špatně utvořeného výchozího zachycení v nelokálních lambda výrazech

Standard jazyka C++ umožňuje, aby výraz lambda v oboru bloku měl výchozí hodnotu capture. Ve Visual Studio 2022 verze 17.1 a novější kompilátor zjistí, kdy v nelokálním lambda výrazu není povoleno výchozí zachytávání. Vygeneruje nové upozornění na úroveň 4, C5253.

Tato změna narušuje kompatibilitu se zdrojem. Platí v jakémkoli režimu, který používá nový procesor lambda: /Zc:lambda, /std:c++20nebo /std:c++latest.

Příklad

V sadě Visual Studio 2022 verze 17.1 teď tento kód vygeneruje chybu:

#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; };
//              ^

Pokud chcete tento problém vyřešit, odeberte výchozí zachytávání:

#pragma warning(error:5253)

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

C4028 je teď C4133 pro operace z funkce na ukazatel

Před verzí 17.1 sady Visual Studio 2022 kompilátor oznámil nesprávnou chybovou zprávu u určitých porovnání ukazatelů na funkci v kódu jazyka C. Nesprávná zpráva byla hlášena při porovnání dvou ukazatelů funkce, které měly stejné počty argumentů, ale nekompatibilní typy. Nyní vydáváme jiné upozornění, které si stěžuje na nekompatibilitu ukazatele na funkci, a ne na neshodu parametrů funkce.

Tato změna narušuje kompatibilitu se zdrojem. Platí, když je kód zkompilován jako C.

Příklad

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)'

Chyba v nezávislém komponentu static_assert

Ve Visual Studiu 2022 verze 17.1 a novější, pokud výraz spojený s static_assert není závislým výrazem, kompilátor vyhodnotí výraz během jeho analýzy. Pokud se výraz vyhodnotí jako false, kompilátor vygeneruje chybu. Dříve, pokud byl static_assert v těle šablony funkce (nebo v těle členské funkce šablony třídy), kompilátor tuto analýzu neprováděl.

Tato změna narušuje kompatibilitu se zdrojem. Platí v jakémkoli režimu, který znamená /permissive- nebo /Zc:static_assert. Tuto změnu chování lze zakázat pomocí možnosti kompilátoru /Zc:static_assert- .

Příklad

V sadě Visual Studio 2022 verze 17.1 a novější teď tento kód způsobí chybu:

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

Pokud chcete tento problém vyřešit, nastavte výraz jako závislý. Příklad:

template<typename>
constexpr bool dependent_false = false;

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

Při této změně kompilátor generuje chybu pouze v případě vytvoření instance šablony f funkce.

Zlepšení shody v prostředí Visual Studio 2022 verze 17.0

Visual Studio 2022 verze 17.0 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.

Upozornění na šířku bitového pole pro typ výčtu

Když deklarujete instanci typu výčtu jako bitové pole, šířka bitového pole musí obsahovat všechny možné hodnoty výčtu. V opačném případě kompilátor vydá diagnostickou zprávu. Podívejte se na tento příklad: Zvažte:

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

struct S {
  E e : 1;
};

Programátor může očekávat, že člen S::e třídy může obsahovat libovolný z explicitně pojmenovaných enum hodnot. Vzhledem k počtu prvků výčtu není možné. Bitové pole nemůže pokrýt rozsah explicitně zadaných hodnot E (koncepčně jde o doménuE). Pokud chcete vyřešit problém, že šířka bitového pole není dostatečně velká pro doménu výčtu, přidá se do MSVC nové upozornění (ve výchozím nastavení vypnuto):

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 };
                                     ^

Toto chování kompilátoru představuje zdrojovou a binární nekompatibilní změnu, která ovlivňuje všechny režimy /std i /permissive.

Chyba při porovnání seřazených ukazatelů proti nullptr nebo 0.

Standard C++ neúmyslně umožnil seřazené porovnání ukazatele proti nullptr nebo 0. Příklad:

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

Dokument WG21 N3478 tento dohled odstranil. Tato změna se implementuje v MSVC. Při kompilaci příkladu pomocí /permissive- (a /diagnostics:caret) se vygeneruje následující chyba:

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

Toto chování kompilátoru představuje změnu, která narušuje zdrojový a binární kód zkompilovaný pomocí /permissive- ve všech režimech /std.

Viz také

Shoda jazyka Microsoft C/C++