/permissive- (Conformité aux normes)

Spécifiez le mode de conformité des normes au compilateur. Utilisez cette option pour vous aider à identifier et résoudre les problèmes de conformité dans votre code, afin de le rendre plus correct et plus portable.

Syntaxe

/permissive-
/permissive

Notes

L’option /permissive- est prise en charge dans Visual Studio 2017 et versions ultérieures. /permissive est pris en charge dans Visual Studio 2019 version 16.8 et versions ultérieures.

Vous pouvez utiliser l’option du /permissive- compilateur pour spécifier le comportement du compilateur conforme aux normes. Cette option désactive les comportements permissifs et définit les options du /Zc compilateur pour une conformité stricte. Dans l’IDE, cette option rend également le code non conforme souligné par le moteur IntelliSense.

L’option /permissive- utilise la prise en charge de la conformité dans la version actuelle du compilateur pour déterminer quelles constructions de langage ne sont pas conformes. L’option ne détermine pas si votre code est conforme à une version spécifique de la norme C++. Pour activer la prise en charge de tous les compilateurs implémentés pour le dernier brouillon standard, utilisez l’option /std:c++latest . Pour limiter la prise en charge du compilateur à la norme C++20 actuellement implémentée, utilisez l’option /std:c++20 . Pour limiter la prise en charge du compilateur à la norme C++17 actuellement implémentée, utilisez l’option /std:c++17 . Pour restreindre la prise en charge du compilateur pour qu’elle corresponde plus étroitement à la norme C++14, utilisez l’option /std:c++14 , qui est la valeur par défaut.

L’option /permissive- est implicitement définie par l’option /std:c++latest à partir de Visual Studio 2019 version 16.8, et dans la version 16.11 par l’option /std:c++20 . /permissive- est nécessaire pour la prise en charge des modules C++20. Votre code n’a peut-être pas besoin de la prise en charge des modules, mais nécessite d’autres fonctionnalités activées sous /std:c++20 ou /std:c++latest. Vous pouvez activer explicitement la prise en charge de l’extension Microsoft à l’aide de l’option sans le /permissive tiret de fin. L’option /permissive doit se présenter après toute option qui définit /permissive- implicitement.

Par défaut, l’option /permissive- est définie dans les nouveaux projets créés par Visual Studio 2017 version 15.5 et versions ultérieures. Elle n’est pas définie par défaut dans les versions antérieures. Lorsque l’option est définie, le compilateur génère des erreurs de diagnostic ou des avertissements lorsque des constructions de langage non standard sont détectées dans votre code. Ces constructions incluent quelques bogues courants dans le code pré-C++11.

L’option /permissive- est compatible avec presque tous les fichiers d’en-tête des derniers kits Windows, tels que le Kit de développement logiciel (SDK) ou le Kit de pilotes Windows (WDK), à partir du Kit de développement logiciel (SDK) Windows Fall Creators (10.0.16299.0). Les versions antérieures du Kit de développement logiciel (SDK) peuvent ne pas être compilées pour /permissive- diverses raisons de conformité du code source. Le compilateur et les kits SDK sont fournis sur différentes chronologies de mise en production. Il existe donc des problèmes restants. Pour connaître des problèmes spécifiques liés au fichier d’en-tête, consultez les problèmes d’en-tête Windows ci-dessous.

L’option /permissive- définit le /Zc:strictStrings/Zc:referenceBindingcomportement conforme, ainsi que /Zc:rvalueCast les options. Ces options sont par défaut non conformes au comportement. Vous pouvez passer des options spécifiques /Zc après /permissive- sur la ligne de commande pour remplacer ce comportement.

Dans les versions du compilateur commençant dans Visual Studio 2017 version 15.3, l’option /permissive- définit l’option /Zc:ternary . Le compilateur implémente également davantage de conditions requises pour la recherche de noms en deux phases. Lorsque l’option /permissive- est définie, le compilateur analyse les définitions de modèle de fonction et de classe et identifie les noms dépendants et non dépendants utilisés dans les modèles. Dans cette version, seule l’analyse des dépendances de nom est effectuée.

À partir de Visual Studio 2022 Update 17.6, l’option /permissive- définit les options et /Zc:externConstexpr les /Zc:lambda options. Dans les versions antérieures, /permissive- n’a pas défini l’une ou l’autre.

Les extensions et les zones de langage spécifiques à l’environnement que la norme laisse à l’implémentation ne sont pas affectées par /permissive-. Par exemple, les mots clés de gestion des exceptions structurées et de convention d’appel spécifiques __declspecà Microsoft, ainsi que les directives ou attributs spécifiques pragma au compilateur ne sont pas marqués par le compilateur en /permissive- mode.

Le compilateur MSVC dans les versions antérieures de Visual Studio 2017 ne prend pas en charge tout le code conforme aux normes C++11, C++14 ou C++17. En fonction de la version de Visual Studio, l’option /permissive- peut ne pas détecter les problèmes dans certains aspects de la recherche de noms en deux phases, lier une référence non const à un init temporaire, traiter l’init de copie comme init direct, autorisant plusieurs conversions définies par l’utilisateur dans l’initialisation, ou des jetons alternatifs pour les opérateurs logiques et d’autres zones de conformité non prises en charge. Pour plus d’informations sur les problèmes de conformité dans Visual C++, consultez Nonstandard Behavior. Pour tirer le meilleur parti de /permissive-, mettez à jour Visual Studio vers la dernière version.

Comment corriger votre code

Voici quelques exemples de code détectés comme non conformes lorsque vous utilisez /permissive-, ainsi que des méthodes suggérées pour résoudre les problèmes.

Utiliser default comme identificateur dans le code natif

void func(int default); // Error C2321: 'default' is a keyword, and
                        // cannot be used in this context

Rechercher des membres dans une base dépendante

template <typename T>
struct B
{
    void f() {}
    template <typename U>
    struct S { void operator()(){ return; } };
};

template <typename T>
struct D : public B<T> // B is a dependent base because its type
                       // depends on the type of T.
{
    // One possible fix for non-template members and function
    // template members is a using statement:
    // using B<T>::f;
    // If it's a type, don't forget the 'typename' keyword.

    void g()
    {
        f(); // error C3861: 'f': identifier not found
        // Another fix is to change the call to 'this->f();'
    }

    void h()
    {
        S<int> s; // C2065 or C3878
        // Since template S is dependent, the type must be qualified
        // with the `typename` keyword.
        // To fix, replace the declaration of s with:
        // typename B<T>::template S<int> s;
        // Or, use this:
        // typename D::template S<int> s;
        s();
    }
};

void h() {
    D<int> d;
    d.g();
    d.h();
}

Utilisation de noms qualifiés dans les déclarations de membre

struct A {
    void A::f() { } // error C4596: illegal qualified name in member
                    // declaration.
                    // Remove redundant 'A::' to fix.
};

Initialiser plusieurs membres d’union dans un initialiseur de membre

union U
{
    U()
        : i(1), j(1) // error C3442: Initializing multiple members of
                     // union: 'U::i' and 'U::j'.
                     // Remove all but one of the initializations to fix.
    {}
    int i;
    int j;
};

Règles de recherche de noms d’ami masquées

Une déclaration en dehors d’une classe peut rendre un ami masqué visible :

// Example 1
struct S {
    friend void f(S *);
};
// Uncomment this declaration to make the hidden friend visible:
// void f(S *); // This declaration makes the hidden friend visible

using type = void (*)(S *);
type p = &f; // error C2065: 'f': undeclared identifier.

L’utilisation d’un littéral nullptr peut empêcher la recherche dépendante de l’argument :

// Example 2
struct S {
    friend void f(S *);
};
void g() {
    // Using nullptr instead of S prevents argument dependent lookup in S
    f(nullptr); // error C3861: 'f': identifier not found

    S *p = nullptr;
    f(p); // Hidden friend now found via argument-dependent lookup.
}

Vous pouvez activer les règles de recherche de nom d’ami masquées indépendamment de l’utilisation /permissive /Zc:hiddenFriendde . Si vous souhaitez un comportement hérité pour la recherche de nom d’ami masqué, mais si vous le souhaitez /permissive- , utilisez l’option /Zc:hiddenFriend- .

Utiliser des énumérations délimitées dans des limites de tableau

enum class Color {
    Red, Green, Blue
};

int data[Color::Blue]; // error C3411: 'Color' is not valid as the size
                       // of an array as it is not an integer type.
                       // Cast to type size_t or int to fix.

Utiliser pour chaque code natif

void func() {
    int array[] = {1, 2, 30, 40};
    for each (int i in array) // error C4496: nonstandard extension
                              // 'for each' used: replace with
                              // ranged-for statement:
                              // for (int i: array)
    {
        // ...
    }
}

Utilisation des attributs ATL

Les attributs ATL spécifiques à Microsoft peuvent entraîner des problèmes sous /permissive-:

// Example 1
[uuid("594382D9-44B0-461A-8DE3-E06A3E73C5EB")]
class A {};

Vous pouvez résoudre le problème à l’aide du formulaire à la __declspec place :

// Fix for example 1
class __declspec(uuid("594382D9-44B0-461A-8DE3-E06A3E73C5EB")) B {};

Exemple plus complexe :

// Example 2
[emitidl];
[module(name="Foo")];

[object, local, uuid("9e66a290-4365-11d2-a997-00c04fa37ddb")]
__interface ICustom {
    HRESULT Custom([in] longl, [out, retval] long*pLong);
    [local] HRESULT CustomLocal([in] longl, [out, retval] long*pLong);
};

[coclass, appobject, uuid("9e66a294-4365-11d2-a997-00c04fa37ddb")]
class CFoo : public ICustom
{};

La résolution nécessite des étapes de génération supplémentaires. Dans ce cas, créez un fichier IDL :

// Fix for example 2
// First, create the *.idl file. The vc140.idl generated file can be
// used to automatically obtain a *.idl file for the interfaces with
// annotation. Second, add a midl step to your build system to make
// sure that the C++ interface definitions are outputted.
// Last, adjust your existing code to use ATL directly as shown in
// the atl implementation section.

-- IDL  FILE--
import "docobj.idl";

[object, local, uuid(9e66a290-4365-11d2-a997-00c04fa37ddb)]
interface ICustom : IUnknown {
    HRESULT Custom([in] longl, [out,retval] long*pLong);
    [local] HRESULT CustomLocal([in] longl, [out,retval] long*pLong);
};

[ version(1.0), uuid(29079a2c-5f3f-3325-99a1-3ec9c40988bb) ]
library Foo {
    importlib("stdole2.tlb");
    importlib("olepro32.dll");

    [version(1.0), appobject, uuid(9e66a294-4365-11d2-a997-00c04fa37ddb)]
    coclass CFoo { interface ICustom; };
}

-- ATL IMPLEMENTATION--
#include <idl.header.h>
#include <atlbase.h>

class ATL_NO_VTABLE CFooImpl : public ICustom,
    public ATL::CComObjectRootEx<CComMultiThreadModel>
{
    public:BEGIN_COM_MAP(CFooImpl)
    COM_INTERFACE_ENTRY(ICustom)
    END_COM_MAP()
};

Arguments d’opérateur conditionnel ambigus

Dans les versions du compilateur avant Visual Studio 2017 version 15.3, le compilateur a accepté les arguments de l’opérateur conditionnel (ou de l’opérateur ternaire) ?: considérés comme ambigus par la norme. En /permissive- mode, le compilateur émet désormais un ou plusieurs diagnostics dans les cas qui ont été compilés sans diagnostics dans les versions antérieures.

Les erreurs courantes qui peuvent résulter de cette modification sont les suivantes :

  • error C2593: 'operator ?' is ambiguous

  • error C2679: binary '?': no operator found which takes a right-hand operand of type 'B' (or there is no acceptable conversion)

  • error C2678: binary '?': no operator found which takes a left-hand operand of type 'A' (or there is no acceptable conversion)

  • error C2446: ':': no conversion from 'B' to 'A'

Un modèle de code classique qui peut provoquer ce problème est quand une classe C fournit à la fois un constructeur non explicite d’un autre type T et un opérateur de conversion non explicite en type T. La conversion du deuxième argument en type du troisième argument est une conversion valide. Il s’agit donc de la conversion du troisième argument en type du deuxième argument. Étant donné que les deux sont valides, il est ambigu selon la norme.

// Example 1: class that provides conversion to and initialization from some type T
struct A
{
    A(int);
    operator int() const;
};

extern bool cond;

A a(42);
// Accepted when /Zc:ternary or /permissive- is not used:
auto x = cond ? 7 : a; // A: permissive behavior prefers A(7) over (int)a
// Accepted always:
auto y = cond ? 7 : int(a);
auto z = cond ? A(7) : a;

Il existe une exception importante à ce modèle commun lorsque T représente l’un des types de chaînes terminées par null (par exemple, const char *, const char16_t *et ainsi de suite) et l’argument réel auquel ?: il s’agit d’un littéral de chaîne de type correspondant. C++17 a changé la sémantique de C++14. Par conséquent, le code de l’exemple 2 est accepté sous /std:c++14 et rejeté sous ou version /std:c++17 ultérieure quand /Zc:ternary ou /permissive- est utilisé.

// Example 2: exception from the above
struct MyString
{
    MyString(const char* s = "") noexcept;  // from char*
    operator const char* () const noexcept; //   to char*
};

extern bool cond;

MyString s;
// Using /std:c++14, /permissive- or /Zc:ternary behavior
// is to prefer MyString("A") over (const char*)s
// but under /std:c++17 this line causes error C2445:
auto x = cond ? "A" : s;
// You can use a static_cast to resolve the ambiguity:
auto y = cond ? "A" : static_cast<const char*>(s);

Vous pouvez également voir des erreurs dans les opérateurs conditionnels avec un argument de type void. Ce cas peut être courant dans les macros de type ASSERT.

// Example 3: void arguments
void myassert(const char* text, const char* file, int line);
// Accepted when /Zc:ternary or /permissive- is not used:
#define ASSERT_A(ex) (void)((ex) ? 1 : myassert(#ex, __FILE__, __LINE__))
// Accepted always:
#define ASSERT_B(ex) (void)((ex) ? void() : myassert(#ex, __FILE__, __LINE__))

Vous pouvez également voir des erreurs dans la métagrammation de modèle, où les types de résultats d’opérateur conditionnel peuvent changer sous /Zc:ternary et /permissive-. Une façon de résoudre ce problème consiste à utiliser std::remove_reference sur le type résultant.

// Example 4: different result types
extern bool cond;
extern int count;
char  a = 'A';
const char  b = 'B';
decltype(auto) x = cond ? a : b; // char without, const char& with /Zc:ternary
const char (&z)[2] = count > 3 ? "A" : "B"; // const char* without /Zc:ternary

Recherche de nom en deux phases

Lorsque l’option /permissive- est définie, le compilateur analyse les définitions de modèle de fonction et de classe, identifiant les noms dépendants et non dépendants utilisés dans les modèles comme requis pour la recherche de noms en deux phases. Dans Visual Studio 2017 version 15.3, l’analyse des dépendances de nom est effectuée. En particulier, les noms non dépendants qui ne sont pas déclarés dans le contexte d’une définition de modèle provoquent un message de diagnostic comme requis par les normes ISO C++. Dans Visual Studio 2017 version 15.7, la liaison de noms non dépendants qui nécessitent une recherche dépendante de l’argument dans le contexte de définition est également effectuée.

// dependent base
struct B {
    void g() {}
};

template<typename T>
struct D : T {
    void f() {
        // The call to g was incorrectly allowed in VS2017:
        g();  // Now under /permissive-: C3861
        // Possible fixes:
        // this->g();
        // T::g();
    }
};

int main()
{
    D<B> d;
    d.f();
}

Si vous souhaitez un comportement hérité pour la recherche en deux phases, mais si vous le souhaitez /permissive- , ajoutez l’option /Zc:twoPhase- .

Problèmes d’en-tête Windows

L’option /permissive- est trop stricte pour les versions des Kits Windows avant windows Fall Creators Update SDK (10.0.16299.0) ou le Kit de pilotes Windows (WDK) version 1709. Nous vous recommandons de mettre à jour les dernières versions des Kits Windows à utiliser /permissive- dans votre code de pilote windows ou périphérique.

Certains fichiers d’en-tête dans le Kit de développement logiciel (SDK) Windows Avril 2018 Update (10.0.17134.0), le Kit de développement logiciel (SDK) Windows Fall Creators Update (10.0.16299.0) ou le Kit de pilotes Windows (WDK) 1709 ont toujours des problèmes qui les rendent incompatibles avec l’utilisation de /permissive-. Pour contourner ces problèmes, nous vous recommandons de limiter l’utilisation de ces en-têtes uniquement aux fichiers de code source qui en ont besoin et de supprimer l’option /permissive- lorsque vous compilez ces fichiers de code source spécifiques.

Ces en-têtes WRL WinRT publiés dans le Kit de développement logiciel (SDK) windows avril 2018 Update (10.0.17134.0) ne sont pas propres avec /permissive-. Pour contourner ces problèmes, n’utilisez /permissive-pas ou utilisez-le /permissive- /Zc:twoPhase- lorsque vous utilisez ces en-têtes :

  • Problèmes dans winrt/wrl/async.h

    C:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0\winrt\wrl\async.h(483): error C3861: 'TraceDelegateAssigned': identifier not found
    C:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0\winrt\wrl\async.h(491): error C3861: 'CheckValidStateForDelegateCall': identifier not found
    C:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0\winrt\wrl\async.h(509): error C3861: 'TraceProgressNotificationStart': identifier not found
    C:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0\winrt\wrl\async.h(513): error C3861: 'TraceProgressNotificationComplete': identifier not found
    
  • Problème dans winrt/wrl/implements.h

    C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\winrt\wrl\implements.h(2086): error C2039: 'SetStrongReference': is not a member of 'Microsoft::WRL::Details::WeakReferenceImpl'
    

Ces en-têtes en mode utilisateur publiés dans le Kit de développement logiciel (SDK) de mise à jour windows avril 2018 (10.0.17134.0) ne sont pas propres avec /permissive-. Pour contourner ces problèmes, n’utilisez /permissive- pas lors de l’utilisation de ces en-têtes :

  • Problèmes dans um/Tune.h

    C:\ProgramFiles(x86)\Windows Kits\10\include\10.0.17134.0\um\tune.h(139): error C3861: 'Release': identifier not found
    C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\um\tune.h(559): error C3861: 'Release': identifier not found
    C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\um\tune.h(1240): error C3861: 'Release': identifier not found
    C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\um\tune.h(1240): note: 'Release': function declaration must be available as none of the arguments depend on a template parameter
    
  • Problème dans um/spddkhlp.h

    C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\um\spddkhlp.h(759): error C3861: 'pNode': identifier not found
    
  • Problèmes dans um/refptrco.h

    C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\um\refptrco.h(179): error C2760: syntax error: unexpected token 'identifier', expected 'type specifier'
    C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\um\refptrco.h(342): error C2760: syntax error: unexpected token 'identifier', expected 'type specifier'
    C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\um\refptrco.h(395): error C2760: syntax error: unexpected token 'identifier', expected 'type specifier'
    

Ces problèmes sont spécifiques aux en-têtes en mode utilisateur dans le Kit de développement logiciel (SDK) Windows Fall Creators Update (10.0.16299.0) :

  • Problème dans um/Query.h

    Lorsque vous utilisez le commutateur du /permissive- compilateur, la tagRESTRICTION structure ne se compile pas en raison du case(RTOr) membre or.

    struct tagRESTRICTION
    {
         ULONG rt;
         ULONG weight;
         /* [switch_is][switch_type] */ union _URes
         {
             /* [case()] */ NODERESTRICTION ar;
             /* [case()] */ NODERESTRICTION or;  // error C2059: syntax error: '||'
             /* [case()] */ NODERESTRICTION pxr;
             /* [case()] */ VECTORRESTRICTION vr;
             /* [case()] */ NOTRESTRICTION nr;
             /* [case()] */ CONTENTRESTRICTION cr;
             /* [case()] */ NATLANGUAGERESTRICTION nlr;
             /* [case()] */ PROPERTYRESTRICTION pr;
             /* [default] */  /* Empty union arm */
         } res;
    };
    

    Pour résoudre ce problème, compilez les fichiers inclus Query.h sans l’option /permissive- .

  • Problème dans um/cellularapi_oem.h

    Lorsque vous utilisez le commutateur du /permissive- compilateur, la déclaration de transfert provoque enum UICCDATASTOREACCESSMODE un avertissement :

    typedef enum UICCDATASTOREACCESSMODE UICCDATASTOREACCESSMODE; // C4471
    

    La déclaration de transfert d’une extension Non étendue enum est une extension Microsoft. Pour résoudre ce problème, compilez des fichiers qui incluent cellularapi_oem.h sans l’option /permissive- , ou utilisez l’option /wd pour silence l’avertissement C4471.

  • Problème dans um/omscript.h

    En C++03, une conversion d’un littéral de chaîne en BSTR (qui est un typedef en wchar_t *) est déconseillée mais autorisée. En C++11, la conversion n’est plus autorisée.

    virtual /* [id] */ HRESULT STDMETHODCALLTYPE setExpression(
         /* [in] */ __RPC__in BSTR propname,
         /* [in] */ __RPC__in BSTR expression,
         /* [in][defaultvalue] */ __RPC__in BSTR language = L"") = 0; // C2440
    

    Pour résoudre ce problème, compilez des fichiers qui incluent omscript.h sans option ou utilisez /Zc:strictStrings- à la /permissive- place.

Pour définir cette option du compilateur dans l'environnement de développement Visual Studio

Dans Visual Studio 2017 version 15.5 et versions ultérieures, procédez comme suit :

  1. Ouvrez la boîte de dialogue Pages de propriétés de votre projet.

  2. Sélectionnez la page de propriétés Propriétés de configuration>C/C++>Langage.

  3. Remplacez la valeur de la propriété du mode Conformité par Oui (/permissive-). Choisissez OK ou Appliquer pour enregistrer vos modifications.

Dans les versions antérieures à Visual Studio 2017 version 15.5, procédez comme suit :

  1. Ouvrez la boîte de dialogue Pages de propriétés de votre projet.

  2. Sélectionnez la page de propriétés Propriétés de configuration>C/C++>Ligne de commande.

  3. Entrez l’option du compilateur /permissive dans la zone Options supplémentaires. Choisissez OK ou Appliquer pour enregistrer vos modifications.

Pour définir cette option du compilateur par programmation

Voir aussi

Options du compilateur MSVC
Syntaxe de la ligne de commande du compilateur MSVC