Partager via


Améliorations de la conformité, changements de comportement et correctifs de bogues de C++ dans Visual Studio 2022

Microsoft C/C++ dans Visual Studio (MSVC) apporte des améliorations de la conformité et des correctifs de bogues dans chaque version. Cet article répertorie les améliorations significatives apportées par version majeure, puis par version. Pour accéder directement aux modifications d’une version spécifique, utilisez les liens Dans cet article en haut de cet article.

Ce document répertorie les modifications apportées à Visual Studio 2022.

Pour les modifications apportées aux versions antérieures de Visual Studio :

Version Lien Améliorations de la conformité
2019 Améliorations de la conformité de C++ dans Visual Studio 2019
2017 Améliorations de la conformité de C++ dans Visual Studio 2017
2003-2015 Nouveautés de Visual C++ entre 2003 et 2015

Améliorations de la conformité dans Visual Studio 2022 version 17.12

Visual Studio 2022 version 17.12 inclut les améliorations de conformité suivantes, les correctifs de bogues et les modifications de comportement dans le compilateur Microsoft C/C++.

Pour obtenir un résumé détaillé des modifications apportées à la bibliothèque de modèles standard, notamment les modifications de conformité, les correctifs de bogues et les améliorations des performances, consultez STL Changelog VS 2022 17.12.

_com_ptr_t::operator bool() est désormais explicite

Il s’agit d’un changement cassant source/binaire.

La conversion implicite vers bool des _com_ptr_t instances peut être surprenante ou entraîner des erreurs du compilateur. Les fonctions de conversion implicite sont déconseillées par les instructions de base C++ (C.164) et contiennent des conversions implicites à la fois bool et Interface*_com_ptr_t . Ces deux conversions implicites peuvent entraîner des ambiguïtés.

Pour vous aider à résoudre ce problème, la conversion en bool est désormais explicite. La conversion en Interface* est inchangée.

Une macro est fournie pour refuser ce nouveau comportement et restaurer la conversion implicite précédente. Compilez avec /D_COM_DISABLE_EXPLICIT_OPERATOR_BOOL pour désactiver cette modification. Nous vous recommandons de modifier le code pour ne pas compter sur les conversions implicites.

Par exemple :

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

Les expressions constantes ne sont plus toujours noexcept en mode permissif

Il s’agit d’un changement cassant source/binaire.

Une expression constante était toujours noexcept, même si elle a impliqué un appel de fonction à une fonction déclarée avec une spécification d’exception potentiellement levée. Cette formulation a été supprimée en C++17, même si le compilateur Microsoft Visual C++ l’a toujours pris en charge en /permissive mode dans toutes les versions du langage C++.

Ce /permissive comportement de mode est supprimé. Les expressions constantes ne reçoivent plus de comportement implicite spécial.

Le noexcept spécificateur sur constexpr les fonctions est désormais respecté dans tous les modes. Cette modification est requise pour une implémentation correcte des résolutions de problèmes de base ultérieures qui reposent sur le comportement standard noexcept .

Par exemple :

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

Améliorations de la conformité dans Visual Studio 2022 version 17.11

Visual Studio 2022 version 17.11 inclut les améliorations de conformité suivantes, les correctifs de bogues et les modifications de comportement dans le compilateur Microsoft C/C++.

Pour obtenir un résumé détaillé des modifications apportées à la bibliothèque de modèles standard, notamment les modifications de conformité, les correctifs de bogues et les améliorations des performances, consultez STL Changelog VS 2022 17.11.

Par P3142R0, il est désormais facile de générer une ligne vide avec println. Cette fonctionnalité est disponible lors de la compilation avec /std:c++latest. Avant cette modification, vous avez écrit : println(""); Maintenant, vous écrivez : println();.

  • println(); équivaut à println(stdout);
  • println(FILE* stream); équivaut à println(stream, "\n");

Implémenté range_formatter

Par P2286R8, range_formatter est désormais implémenté. Cette fonctionnalité est disponible lors de la compilation avec /std:c++latest.

Améliorations de la conformité dans Visual Studio 2022 version 17.10

Visual Studio 2022 version 17.10 inclut les améliorations de conformité suivantes, les correctifs de bogues et les modifications de comportement dans le compilateur Microsoft C/C++.

Pour obtenir un résumé détaillé des modifications apportées à la bibliothèque de modèles standard, notamment les modifications de conformité, les correctifs de bogues et les améliorations des performances, veuillez consulter le Journal des modifications STL VS 2022 17.10.

Spécialisation de l’opérateur de conversion avec un type de retour explicitement spécifié

Le compilateur spécialisait les opérateurs de conversion de manière incorrecte dans certains cas, ce qui pouvait entraîner un type de retour incompatible. Ces spécialisations non valides ne se produisent plus. Ceci est un changement cassant de code source.

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

Nous avons ajouté la prise en charge de #elifdef et de #elifndef

Prise en charge ajoutée pour P2334R1 WG21 (C++23) et WG14 N2645 (C++23) ayant introduit les directives de préprocesseur #elifdef et #elifndef . Nécessite /std:clatest ou /std:c++latest.

Avant :

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

Après :

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

Application de _Alignas sur un type structuré en langage C

S’applique au langage C (C17 et versions ultérieures). Également ajouté à Microsoft Visual Studio 17.9

Dans les versions de Visual C++ antérieures à la version 17.9 de Visual Studio 2022, si le spécificateur _Alignas était adjacent à un type structuré dans une déclaration, il n’était pas appliqué correctement selon la norme 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");

Selon la norme ISO-C, ce code doit se compiler sans que static_assert émette de diagnostic.

La directive _Alignas s’applique uniquement à la variable membre member1. Elle ne doit pas modifier l’alignement de struct Inner. Toutefois, avant Visual Studio 17.9.1, le diagnostic « alignement incorrect » était émis. Le compilateur alignait member2 à un décalage de 32 octets au sein du type struct Outer.

C’est un changement cassant binaire. Par conséquent, un avertissement est maintenant émis lorsque cette modification prend effet. L’avertissement C5274 est maintenant émis au niveau d’avertissement 1 pour l’exemple précédent : warning C5274: behavior change: _Alignas no longer applies to the type 'Inner' (only applies to declared data objects).

En outre, dans les versions précédentes de Visual Studio, lorsque le spécificateur _Alignas était adjacent à une déclaration de type anonyme, il était ignoré.

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

Auparavant, les deux instructions static_assert échouaient lors de la compilation de ce code. À présent, le code se compile mais émet les avertissements de niveau 1 suivants :

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)

Pour obtenir le comportement précédent, remplacez _Alignas(N) par __declspec(align(N)). Contrairement à _Alignas, declspec(align) s’applique au type.

Avertissement amélioré C4706

Ceci est un changement cassant de code source. Auparavant, le compilateur ne détectait pas la convention d’enveloppement d’une affectation entre parenthèses, si une affectation était prévue, pour supprimer l’avertissement C4706 sur l’affectation dans une expression conditionnelle. Maintenant, le compilateur détecte les parenthèses, puis supprime l’avertissement.

#pragma warning(error: 4706)

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

   int value = 9;
};

Le compilateur émet désormais également l’avertissement dans les cas où la fonction n’est pas référencée. Auparavant, étant donné que mf est une fonction inline qui n’est pas référencée, l’avertissement C4706 n’était pas émis pour ce code. À présent, l’avertissement est émis :

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

Pour corriger cet avertissement, utilisez un opérateur d’égalité, value == 9, si c’est ce qui était prévu. Sinon, enveloppez l’affectation entre parenthèses, (value = 9), si une affectation est prévue. Sinon, puisque la fonction n’est pas référencée, supprimez-la.

Améliorations de la conformité dans Visual Studio 2022 version 17.9

Visual Studio 2022 version 17.9 contient les améliorations de conformité, correctifs de bogues et changements de comportement suivants dans le compilateur Microsoft C/C++.

Pour obtenir un résumé plus complet des modifications apportées à la bibliothèque de modèles standard, veuillez consulter le journal des modifications STL VS 2022 17.9.

Application de _Alignas sur un type structuré en langage C

Dans les versions de Visual C++ antérieures à la version 17.9 de Visual Studio 2022, quand _Alignas apparaissait près d’un type de structure dans une déclaration, il n’était pas appliqué correctement selon la norme ISO-C. Par exemple :

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

Selon la norme ISO-C, ce code doit se compiler sans que static_assert émette de diagnostic. La directive _Alignas s’applique uniquement à la variable membre member1. Elle ne doit pas modifier l’alignement de struct Inner. Toutefois, avant la version 17.9.1 de Visual Studio, le diagnostic « alignement incorrect » était émis. Le compilateur alignait member2 sur un décalage de 32 octets dans struct Outer.

La correction de ce problème est un changement cassant binaire. Par conséquent, lorsque ce changement de comportement est appliqué, un avertissement est émis. Pour le code précédent, l’avertissement C5274, « _Alignas ne s’applique plus au type « Interne » (s’applique uniquement aux objets de données déclarés) » est maintenant émis au niveau d’avertissement 1.

En outre, dans les versions précédentes de Visual Studio, _Alignas était ignoré quand il apparaissait près d’une déclaration. Par exemple :

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

Auparavant, les deux instructions static_assert échouaient lors de la compilation de ce code. À présent, le code se compile mais avec les avertissements de niveau 1 suivants :

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)

Si vous recherchez le comportement précédent, remplacez _Alignas(N) par __declspec(align(N)). Contrairement à _Alignas, declspec(align) peut être appliqué à un type.

__VA_OPT__ est activé comme extension sous /Zc:preprocessor

__VA_OPT__ a été ajouté à C++20 et à C23. Avant son ajout, il n’y avait pas de moyen standard d’ignorer une virgule dans une macro variadique. Pour améliorer la compatibilité descendante, __VA_OPT__ est activé sous le préprocesseur /Zc:preprocessor basé sur un jeton sur toutes les versions de langage.

Par exemple, ceci se compile maintenant sans erreur :

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

Langage C23

Pour C23, les éléments suivants sont disponibles lors de l’utilisation du commutateur du compilateur /std:clatest :

typeof
typeof_unqual

Les éléments suivants sont disponibles pour toutes les versions du langage C :

__typeof__
__typeof_unqual__

Bibliothèque C++ standard

Fonctionnalités C++23

  • formattable, range_format, format_kind et set_debug_format() comme partie des plages de mise en forme P2286R8
  • <mdspan> selon P0009R18 et les modifications de formulation suivantes qui ont été appliquées à la norme C++23.
  • format() pointeurs selon P2510R3.

Améliorations de la conformité dans Visual Studio 2022 version 17.8

Dans Visual Studio 2022 version 17.8, les améliorations de conformité, correctifs de bogues et changements de comportement suivants ont été apportés au compilateur Microsoft C/C++.

/FU émet une erreur

Le compilateur C continuait d’accepter l’option /FU alors qu’il ne prenait plus en charge la compilation managée depuis un certain temps. Il émet maintenant une erreur. Les projets qui passent cette option doivent la limiter aux projets C++/CLI.

Bibliothèque standard C++

Les modules C++23 nommés std et std.compat sont désormais disponibles lors de la compilation avec /std:c++20.

Pour obtenir un résumé plus complet des modifications apportées à la bibliothèque standard C++, consultez le journal des modifications STL VS 2022 17.8.

Améliorations de la conformité dans Visual Studio 2022 version 17.7

Dans Visual Studio 2022 version 17.7, les améliorations de conformité, correctifs de bogues et changements de comportement mis en évidence ci-après ont été apportés au compilateur Microsoft C/C++.

Ajout de /std:clatest au compilateur C

Ce commutateur se comporte comme le commutateur /std:c++latest pour le compilateur C++. Le commutateur active toutes les fonctionnalités du compilateur et de la bibliothèque standard actuellement implémentées pour le prochain projet du standard C ainsi que certaines fonctionnalités expérimentales et en cours.

Bibliothèque standard C++

La bibliothèque <print> est désormais prise en charge. Consultez Sortie au format P2093R14.

Implémentation de views::cartesian_product.

Pour obtenir un résumé plus complet des modifications apportées à la bibliothèque de modèles standard consultez le journal des modifications STL VS 2022 17.7.

Conformité de using

Auparavant, avec la directive using, des noms d’espaces de noms utilisés pouvaient rester visibles par erreur. Cela pouvait entraîner une recherche de nom non qualifiée pour trouver un nom dans un espace de noms, même en l’absence de directive using active.

Voici quelques exemples du nouveau comportement et de l’ancien.
Les références dans les commentaires suivants à « (1) » signifient l’appel à f<K>(t) dans l’espace de noms 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>()); 
    } 
} 

Le même problème sous-jacent peut entraîner le rejet du code précédemment compilé :

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

Améliorations de la conformité dans Visual Studio 2022 version 17.6

Visual Studio 2022 version 17.6 contient les améliorations de conformité, les correctifs de bogues et les changements de comportement suivants apportés au compilateur Microsoft C/C++.

Les affectations composées volatile ne sont plus déconseillées

C++20 déconseillait l’application de certains opérateurs aux types qualifiés avec volatile. Par exemple, lorsque le code suivant est compilé avec cl /std:c++20 /Wall test.cpp :

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

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

Dans C++20, les opérateurs d’assignation composée (opérateurs avec la forme @=) étaient déconseillés. Dans C++23, les opérateurs composés exclus dans C++20 ne sont plus déconseillés. Par exemple, dans C++23, le code suivant ne génère pas d’avertissement, comme c’était le cas dans C++20 :

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

Pour plus d’informations sur ce changement, consultez CWG:2654

La réécriture de l’égalité dans les expressions est un changement moins cassant (P2468R2)

Dans C++20, P2468R2 a modifié le compilateur pour accepter du code tel que :

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

Le compilateur accepte ce code, ce qui signifie que le compilateur est plus strict avec du code tel que :

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

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

La version 17.5 du compilateur accepte ce programme. La version 17.6 du compilateur la rejette. Pour résoudre ce problème, ajoutez const à operator== pour supprimer l’ambiguïté. Vous pouvez également ajouter un operator!= correspondant à la définition, comme illustré dans l’exemple suivant :

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

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

Les versions 17.5 et 17.6 du compilateur Microsoft C/C++ acceptent le programme précédent et les appels S::operator== dans les deux versions.

Le modèle de programmation général décrit dans P2468R2 indique que s’il existe un operator!= correspondant pour un type, il supprime généralement le comportement de la réécriture. L’ajout d’un operator!= correspondant est le correctif suggéré pour le code précédemment compilé en C++17. Pour plus d’informations, consultez Modèle de programmation.

Améliorations de la conformité dans Visual Studio 2022 version 17.4

Visual Studio 2022 version 17.4 contient les améliorations de conformité, les correctifs de bogues et les changements de comportement suivants dans le compilateur Microsoft C/C++.

Types sous-jacents d’enum non délimitée sans type fixe

Dans les versions de Visual Studio antérieures à Visual Studio 2022 version 17.4, le compilateur C++ ne déterminait pas correctement le type sous-jacent d’une énumération non délimitée sans type de base fixe. Sous /Zc:enumTypes, nous implémentons désormais correctement le comportement standard.

La norme C++ nécessite que le type sous-jacent d’une enum soit suffisamment grand pour contenir tous les énumérateurs dans cette enum. Des énumérateurs suffisamment grands peuvent définir le type sous-jacent de l’enum sur unsigned int, long long ou unsigned long long. Auparavant, ces types d’enum avaient toujours un type sous-jacent de int dans le compilateur Microsoft, quelles que soient les valeurs d’énumérateur.

Lorsqu’elle est activée, l’option /Zc:enumTypes est une changement cassant potentiel de source et de binaire. Elle est désactivée par défaut, et non activée par /permissive-, car le correctif peut affecter la compatibilité binaire. Certains types d’énumération changent de taille lorsque le correctif conforme est activé. Certains en-têtes SDK Windows incluent de telles définitions d’énumération.

Exemple

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

Types d’énumérateurs dans une définition d’enum sans type sous-jacent fixe

Dans les versions de Visual Studio antérieures à Visual Studio 2022 version 17.4, le compilateur C++ ne modélisait pas correctement les types d’énumérateurs. Il pouvait supposer un type incorrect dans les énumérations sans type sous-jacent fixe avant l’accolade fermante de l’énumération. Sous /Zc:enumTypes, le compilateur implémente désormais correctement le comportement standard.

La Norme C++ spécifie qu’au sein d’une définition d’énumération sans type sous-jacent fixe, les initialiseurs déterminent les types des énumérateurs. Ou bien, pour les énumérateurs sans initialiseur, par le type de l’énumérateur précédent (en tenant compte du dépassement). Auparavant, ces énumérateurs recevaient toujours le type déduit de l’énumération, avec un espace réservé pour le type sous-jacent (généralement int).

Lorsqu’elle est activée, l’option /Zc:enumTypes est une changement cassant potentiel de source et de binaire. Elle est désactivée par défaut, et non activée par /permissive-, car le correctif peut affecter la compatibilité binaire. Certains types d’énumération changent de taille lorsque le correctif conforme est activé. Certains en-têtes SDK Windows incluent de telles définitions d’énumération.

Exemple

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

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

Dans cet exemple, l’énumérateur A doit avoir le type char avant l’accolade fermante de l’énumération. Par conséquent, B doit être initialisé avec sizeof(char). Avant le correctif /Zc:enumTypes, A avait un type d’énumération Enum avec un type sous-jacent déduit int, et B était initialisé avec sizeof(Enum) ou 4.

Améliorations de la conformité dans Visual Studio 2022 version 17.3

Visual Studio 2022 version 17.3 contient les améliorations de conformité, les correctifs de bogues et les changements de comportement suivants dans le compilateur Microsoft C/C++.

C : Amélioration de la vérification de la compatibilité des modificateurs entre les pointeurs

Le compilateur C ne comparait pas correctement les modificateurs entre les pointeurs, en particulier void*. Ce défaut pouvait entraîner un diagnostic incorrect d’incompatibilité entre const int** et void*, et de compatibilité entre int* volatile* et void*.

Exemple

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
}

Améliorations de la conformité dans Visual Studio 2022 version 17.2

Visual Studio 2022 version 17.2 contient les améliorations de conformité, les correctifs de bogues et les changements de comportement suivants dans le compilateur Microsoft C/C++.

Avertissements de caractères bidirectionnels inachevés

Visual Studio 2022 version 17.2 ajoute un avertissement C5255 de niveau 3 pour les caractères bidirectionnels Unicode inachevés dans des commentaires et des chaînes. Cet avertissement répond à un souci de sécurité décrit dans Trojan Source : Invisible Vulnerabilities par Nicholas Boucher et Ross Anderson. Pour plus d’informations sur les caractères bidirectionnels Unicode, consultez Unicode® Standard Annex #9: UNICODE BIDIRECTIONAL ALGORITHM.

L’avertissement C5255 ne concerne que les fichiers qui, après conversion, contiennent des caractères bidirectionnels Unicode. Cet avertissement s’appliquant aux fichiers UTF-8, UTF-16 et UTF-32, l’encodage source approprié doit être fourni. Cette modification est un changement cassant de source.

Exemple (avant/après)

Dans les versions de Visual Studio antérieures à Visual Studio 2022 version 17.2, un caractère bidirectionnel inachevé ne générait pas d’avertissement. Visual Studio 2022 version 17.2 génère l’avertissement 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 tiebreak

Visual Studio 2022 version 17.2 corrige un bogue dans les règles de tiebreak <charconv> from_chars() float qui produisaient des résultats incorrects. Ce bogue affectait les chaînes décimales qui se trouvaient au milieu exact de valeurs float consécutives à l’intérieur d’une plage étroite. (Les valeurs les plus petites et les plus importantes affectées ont été 32768.009765625 et 131071.98828125, respectivement.) La règle de cravate voulait arrondir à « même », et « même » était « down », mais l’implémentation a mal arrondi « up » (double n’a pas été affectée).) Pour plus d’informations et d’implémentation, consultez microsoft/STL#2366.

Cette modification affecte le comportement du runtime dans la plage de cas spécifiée :

Exemple

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

Dans les versions antérieures à Visual Studio 2022 version 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.

Dans Visual Studio 2022 versions 17.2 et ultérieures :

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__ rend __STDC__ disponible pour C

La norme C exige qu’une implémentation de C conforme définisse __STDC__ comme 1. En raison du comportement de l’UCRT, qui n’expose pas les fonctions POSIX quand __STDC__ est 1, il n’est pas possible de définir cette macro pour C par défaut sans introduire de changements cassants dans les versions de langage stable. Visual Studio 2022 versions 17.2 et ultérieures ajoutent une option de conformité /Zc:__STDC__ qui définit cette macro. Il n’existe aucune version négative de l’option. Actuellement, nous prévoyons d’utiliser cette option par défaut pour les futures versions de C.

Cette modification est un changement cassant de source. Il s’applique lorsque le mode C11 ou C17 est activé (/std:c11 ou /std:c17) et /Zc:__STDC__ est spécifié.

Exemple

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

*/

Avertissement pour les accolades manquantes

L’avertissement C5246 signale des accolades manquantes pendant l’initialisation agrégée d’un sous-objet. Avant Visual Studio 2022 version 17.2, l’avertissement ne gérait pas le cas d’un struct ou d’une union anonymes.

Cette modification est un changement cassant de source. Elle s’applique lorsque l’avertissement désactivé par défaut C5246 est activé.

Exemple

Dans Visual Studio 2022 versions 17.2 et ultérieures, ce code provoque désormais une erreur :

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

Pour résoudre ce problème, ajoutez des accolades à l’initialiseur :

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

Améliorations de la conformité dans Visual Studio 2022 version 17.1

Visual Studio 2022 version 17.1 contient les améliorations de conformité, les correctifs de bogues et les changements de comportement suivants dans le compilateur Microsoft C/C++.

Détecter les valeurs par défaut de capture mal formées dans les expressions lambda non locales

La Norme C++ autorise uniquement une expression lambda dans une portée de bloc à avoir une capture par défaut. Dans Visual Studio 2022 versions 17.1 et ultérieures, le compilateur détecte quand une valeur par défaut de capture n’est pas autorisée dans une expression lambda non locale. Il émet un nouvel avertissement de niveau 4, C5253.

Cette modification est un changement cassant de source. Elle s’applique en tout mode qui utilise le nouveau processeur lambda : /Zc:lambda, /std:c++20 ou /std:c++latest.

Exemple

Dans Visual Studio 2022 version 17.1, ce code émet désormais une erreur :

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

Pour résoudre ce problème, supprimez le défaut de capture :

#pragma warning(error:5253)

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

C4028 est maintenant C4133 pour les opérations de fonction à pointeur

Avant Visual Studio 2022 version 17.1, le compilateur générait un message d’erreur incorrect sur certaines comparaisons de pointeur à fonction dans le code C. Le message incorrect était généré lorsque vous compariez deux pointeurs de fonction qui avaient le même nombre d’arguments mais des types incompatibles. Désormais, nous émettons un avertissement différent dénonçant une incompatibilité de pointeur à fonction plutôt qu’une discordance de paramètre de fonction.

Cette modification est un changement cassant de source. Elle s’applique lorsque le code est compilé en tant que C.

Exemple

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

Erreur sur un élément static_assert non dépendant

Dans Visual Studio 2022 versions 17.1 et ultérieures, si l’expression associée à static_assert n’est pas une expression dépendante, le compilateur évalue l’expression quand elle est analysée. Si l’expression prend la valeur false, le compilateur émet une erreur. Auparavant, si la static_assert se trouvait dans le corps d’un modèle de fonction (ou dans le corps d’une fonction membre d’un modèle de classe), le compilateur n’effectuait pas cette analyse.

Cette modification est un changement cassant de source. Elle s’applique en tout mode impliquant /permissive- ou /Zc:static_assert. Ce changement de comportement peut être désactivé à l’aide de l’option de compilateur de /Zc:static_assert-.

Exemple

Dans Visual Studio 2022 versions 17.1 et ultérieures, ce code provoque désormais une erreur :

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

Pour résoudre ce problème, rendez l’expression dépendante. Par exemple :

template<typename>
constexpr bool dependent_false = false;

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

Avec cette modification, le compilateur n’émet une erreur que si le modèle de fonction f est instancié.

Améliorations de la conformité dans Visual Studio 2022 version 17.0

Visual Studio 2022 version 17.0 contient les améliorations de conformité, les correctifs de bogues et les changements de comportement suivants dans le compilateur Microsoft C/C++.

Avertissement sur la largeur de champ de bits pour un type d’énumération

Lorsque vous déclarez une instance d’un type d’énumération en tant que champ de bits, la largeur du champ de bits doit pouvoir accueillir toutes les valeurs possibles de l’énumération. Sinon, le compilateur émet un message de diagnostic. Prenons l’exemple suivant :

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

struct S {
  E e : 1;
};

Un programmeur pourrait s’attendre à ce que le membre de classe S::e puisse contenir l’une des valeurs enum nommées explicitement. Compte tenu du nombre d’éléments d’énumération, ce n’est pas possible. Le champ de bits ne peut pas couvrir la plage de valeurs explicitement fournies de E (conceptuellement, le domaine de E). Pour résoudre le problème lié au fait que la largeur du champ de bits n’est pas suffisante pour le domaine de l’énumération, un nouvel avertissement (désactivé par défaut) est ajouté à 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 };
                                     ^

Ce comportement de compilateur est un changement cassant de source et de binaire qui affecte tous les modes /std et /permissive.

Erreur lors de la comparaison de pointeur ordonné à nullptr ou 0

La Norme C++ autorisait par inadvertance une comparaison de pointeur ordonné à nullptr ou 0. Par exemple :

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

Le document WG21 N3478 a supprimé cette omission. Cette modification est implémentée dans MSVC. Lorsque l’exemple est compilé à l’aide /permissive- (et /diagnostics:caret), il émet l’erreur suivante :

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

Ce comportement de compilateur est un changement cassant de source et de binaire qui affecte le code compilé à l’aide de /permissive- dans tous les modes /std.

Voir aussi

Conformité du langage Microsoft C/C++