/permissive-
(Conformité aux normes)
Spécifiez le mode de conformité aux normes pour le compilateur. Utilisez cette option pour vous aider à identifier et à résoudre les problèmes de conformité dans votre code, afin de le rendre à la fois 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 ultérieures.
Vous pouvez utiliser l’option du compilateur pour spécifier le /permissive-
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 permet également au moteur IntelliSense de souligner le code non conforme.
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 la dernière version de la version préliminaire de la norme, 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 limiter la prise en charge du compilateur afin 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 requis 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 /permissive
sans le tiret de fin. L’option /permissive
doit venir après toute option qui définit /permissive-
implicitement.
Par défaut, l’option est définie dans les /permissive-
nouveaux projets créés par Visual Studio 2017 version 15.5 et versions ultérieures. Il n’est pas défini 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 des bogues courants dans le code antérieur à 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 sous /permissive-
pour différentes raisons de conformité du code source. Le compilateur et les KITS de développement logiciel (SDK) sont fournis selon des chronologies de publication différentes, il reste donc des problèmes. Pour connaître des problèmes spécifiques liés au fichier d’en-tête, consultez Problèmes d’en-tête Windows ci-dessous.
L’option /permissive-
définit les /Zc:referenceBinding
options , /Zc:strictStrings
et /Zc:rvalueCast
sur un comportement conforme. Ces options sont par défaut un comportement non conforme. 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.
Les extensions spécifiques à l’environnement et les zones de langage que la norme laisse à l’implémentation ne sont pas affectées par /permissive-
. Par exemple, les mots clés __declspec
spécifiques à Microsoft, la convention d’appel et la gestion structurée des exceptions, ainsi que les directives ou attributs spécifiques au pragma
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. Selon la version de Visual Studio, l’option /permissive-
peut ne pas détecter des problèmes dans certains aspects de la recherche de noms en deux phases, liant une référence non const à une copie temporaire, traitant l’init de copie comme un 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é comme non conforme 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 membres
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 membres
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 nom d’ami masqué
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 de 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é indépendamment de à l’aide /Zc:hiddenFriend
de /permissive
. Si vous souhaitez un comportement hérité pour la recherche de nom d’ami masqué, mais que vous souhaitez /permissive-
un comportement, utilisez l’option /Zc:hiddenFriend-
.
Utiliser des énumérations étendues 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 chacun d’eux dans le 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 d’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 ambigus de l’opérateur conditionnel
Dans les versions du compilateur antérieures à 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 à partir 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 en va de même pour 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 courant lorsque T représente l’un des types de chaînes terminés par null (par exemple, const char *
, const char16_t *
et ainsi de suite) et que l’argument réel à ?:
est un littéral de chaîne du 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 /std:c++17
ou ultérieur 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étaprogrammation de modèle, où les types de résultats de l’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, en 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 noms 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 des arguments 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 que vous souhaitez /permissive-
un comportement, 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 le Kit de développement logiciel (SDK) Windows Fall Creators Update (10.0.16299.0) ou le Kit de pilotes Windows (WDK) version 1709. Nous vous recommandons d’effectuer une mise à jour vers les dernières versions des kits Windows à utiliser /permissive-
dans le code de votre pilote Windows ou de votre périphérique.
Certains fichiers d’en-tête dans le Kit de développement logiciel (SDK) Windows Avril 2018 (10.0.17134.0), windows Fall Creators Update (10.0.16299.0) ou le Kit de pilotes Windows (WDK) 1709 présentent 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 WinRT WRL publiés dans le Kit de développement logiciel (SDK) windows d’avril 2018 (10.0.17134.0) ne sont pas propres avec /permissive-
. Pour contourner ces problèmes, n’utilisez /permissive-
pas ou utilisez /permissive-
avec /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 de mode utilisateur publiés dans le Kit de développement logiciel (SDK) De mise à jour Windows d’avril 2018 (10.0.17134.0) ne sont pas propres avec /permissive-
. Pour contourner ces problèmes, n’utilisez /permissive-
pas lorsque vous utilisez 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 de 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 de
/permissive-
compilateur, latagRESTRICTION
structure ne se compile pas en raison ducase(RTOr)
membreor
.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 qui incluent
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 deenum UICCDATASTOREACCESSMODE
provoque un avertissement :typedef enum UICCDATASTOREACCESSMODE UICCDATASTOREACCESSMODE; // C4471
La déclaration de transfert d’un non étendue
enum
est une extension Microsoft. Pour résoudre ce problème, compilez les fichiers qui incluentcellularapi_oem.h
sans l’option/permissive-
ou utilisez l’option pour faire taire l’avertissement/wd
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 enwchar_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 l’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 :
Ouvrez la boîte de dialogue Pages de propriétés de votre projet.
Sélectionnez la page de propriétés De> configurationC/C++>Language.
Remplacez la valeur de la propriété Mode de 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 :
Ouvrez la boîte de dialogue Pages de propriétés de votre projet.
Sélectionnez la page de propriétés de>la ligne de commandeC/C++>Propriétés de configuration.
Entrez l’option /permissive- compiler dans la zone Options supplémentaires . Choisissez OK ou Appliquer pour enregistrer vos modifications.
Pour définir cette option du compilateur par programmation
- Consultez AdditionalOptions.
Voir aussi
Options du compilateur MSVC
Syntaxe Command-Line du compilateur MSVC