/permissive/ (Conformidad de los estándares)

Especifique el modo de conformidad de estándares para el compilador. Use esta opción para ayudarle a identificar y corregir problemas de conformidad en el código, para que sea más correcto y portátil.

Sintaxis

/permissive-
/permissive

Comentarios

La /permissive- opción se admite en Visual Studio 2017 y versiones posteriores. /permissivese admite en Visual Studio versión 16.8 y posteriores de 2019.

Puede usar la opción del compilador para especificar el comportamiento del compilador conforme a los /permissive- estándares. Esta opción deshabilita los comportamientos permisivos y establece las opciones del /Zc compilador para una conformidad estricta. En el IDE, esta opción también hace que el motor de IntelliSense subrayado código no conforme.

La opción usa la compatibilidad de conformidad en la versión actual del compilador para determinar qué construcciones /permissive- de lenguaje no son conformes. La opción no determina si el código se ajusta a una versión específica del estándar de C++. Para habilitar toda la compatibilidad con el compilador implementado para el borrador de estándar más reciente, use la /std:c++latest opción . Para restringir la compatibilidad del compilador con el estándar C++20 implementado actualmente, use la /std:c++20 opción . Para restringir la compatibilidad del compilador con el estándar C++17 implementado actualmente, use la /std:c++17 opción . Para restringir la compatibilidad del compilador para que coincida más estrechamente con el estándar de C++14, use la opción /std:c++14 , que es el valor predeterminado.

La opción se establece implícitamente mediante la opción a partir de la versión /permissive-/std:c++latest 16.8 de Visual Studio 2019 y de la versión 16.11. /std:c++20 /permissive- es necesario para la compatibilidad con módulos de C++20. Quizás el código no necesita compatibilidad con módulos, pero requiere otras características habilitadas en /std:c++20 o /std:c++latest . Puede habilitar explícitamente la compatibilidad con extensiones de Microsoft mediante la /permissive opción sin el guion final.

De forma predeterminada, la opción se establece en los nuevos proyectos creados /permissive- por Visual Studio 2017 versión 15.5 y versiones posteriores. No se establece de forma predeterminada en versiones anteriores. Cuando se establece la opción , el compilador genera errores de diagnóstico o advertencias cuando se detectan construcciones de lenguaje no estándar en el código. Estas construcciones incluyen algunos errores comunes en el código anterior a C++11.

La opción es compatible con casi todos los archivos de encabezado de los kits de Windows más recientes, como el Kit de desarrollo de software (SDK) o el kit de controladores de Windows (WDK), a partir del SDK de /permissive- fall Creators de Windows (10.0.16299.0). Es posible que las versiones anteriores del SDK no se compilen en /permissive- por diversas razones de conformidad con el código fuente. El compilador y los SDK se envían en diferentes escalas de tiempo de versión, por lo que hay algunos problemas restantes. Para ver problemas específicos del archivo de encabezado, Windows problemas de encabezado a continuación.

La /permissive- opción establece las opciones , y en el comportamiento /Zc:referenceBinding/Zc:strictStrings/Zc:rvalueCast conforme. Estas opciones tienen como valor predeterminado un comportamiento no conforme. Puede pasar opciones específicas /Zc después de en la línea de comandos para invalidar este /permissive- comportamiento.

En las versiones del compilador a partir Visual Studio versión 15.3 de 2017, la opción /permissive- establece la /Zc:ternary opción . El compilador también implementa más de los requisitos para la consulta de nombres en dos fases. Cuando se establece la opción , el compilador analiza las definiciones de plantilla de función y clase e identifica los nombres dependientes y no dependientes que se usan /permissive- en las plantillas. En esta versión, solo se realiza el análisis de dependencias de nombres.

Las extensiones específicas del entorno y las áreas de lenguaje que deja el estándar hasta la implementación no se ven afectadas por /permissive- . Por ejemplo, las palabras clave específicas de Microsoft, la convención de llamada y el control estructurado de excepciones, y las directivas pragma o atributos específicos del compilador no están marcados por el compilador __declspec en /permissive- modo .

No todo el código conforme a los estándares de C++11, C++14 o C++17 es compatible con el compilador de MSVC en todas las versiones de Visual Studio 2017. En función de la versión de Visual Studio, la opción puede no detectar problemas en algunos aspectos de la búsqueda de nombres en dos fases, enlazar una referencia no const a una temporal, tratar copy init como inicialización directa, permitir varias conversiones definidas por el usuario en la inicialización, tokens alternativos para operadores lógicos y otras áreas de conformidad no /permissive- admitidas. Para obtener más información sobre los problemas de conformidad de Visual C++, vea Nonstandard Behavior. Para sacar el máximo partido de /permissive- , actualice Visual Studio a la versión más reciente.

Cómo corregir el código

Estos son algunos ejemplos de código que se detecta como no conforme cuando se usa , junto con formas /permissive- sugeridas de corregir los problemas.

Usar el valor predeterminado como identificador en código nativo

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

Buscar miembros en una base dependiente

template <typename T>
struct B {
    void f();
};

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 is to uncomment the following line.
    // If this is a type, don't forget the 'typename' keyword.
    // using B<T>::f;

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

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

Uso de nombres completos en declaraciones de miembro

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

Inicializar varios miembros de unión en un inicializador de miembro

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

Reglas de búsqueda de nombres de confianza ocultos

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

Puede habilitar las reglas de búsqueda de nombres de confianza ocultos independientemente /permissive de mediante /Zc:hiddenFriend . Si desea un comportamiento heredado para la búsqueda oculta de nombres de confianza, pero de lo contrario desea /permissive- un comportamiento, use la /Zc:hiddenFriend- opción .

Uso de enumeraciones con ámbito en límites de matriz

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.

Usar para cada en código nativo

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)
    {
        // ...
    }
}

Uso de atributos ATL

// Example 1
[uuid("594382D9-44B0-461A-8DE3-E06A3E73C5EB")]
class A {};
// Fix for example 1
class __declspec(uuid("594382D9-44B0-461A-8DE3-E06A3E73C5EB")) B {};
// 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
{};
// 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()
};

Argumentos ambiguos del operador condicional

En las versiones del compilador anteriores Visual Studio la versión 15.3 de 2017, el compilador aceptaba argumentos para el operador condicional (u operador ternario) que el estándar considera ?: ambiguos. En /permissive- modo , el compilador ahora emite uno o varios diagnósticos en casos que se compilaron sin diagnósticos en versiones anteriores.

Entre los errores comunes que pueden producirse a partir de este cambio se incluyen:

  • 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 patrón de código típico que puede provocar este problema es cuando alguna clase C proporciona un constructor no explícito de otro tipo T y un operador de conversión no explícito al tipo T. En este caso, la conversión del segundo argumento al tipo del tercer argumento y la conversión del tercer argumento al tipo del segundo argumento son conversiones válidas. Dado que ambos son válidos, es ambiguo según el estándar.

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

Hay una excepción importante a este patrón común cuando T representa uno de los tipos de cadena terminadas en NULL (por ejemplo, , , y así sucesivamente) y el argumento real para es un literal de cadena del tipo const char *const char16_t *?: correspondiente. C++17 ha cambiado la semántica de C++14. Como resultado, el código del ejemplo 2 se acepta en y se rechaza en o /std:c++14 posterior cuando se usa o /std:c++17/Zc:ternary/permissive- .

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

Otro caso en el que puede ver errores es en operadores condicionales con un argumento de tipo void . Este caso puede ser común en macros de tipo 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__))

También puede ver errores en la metaprogramación de plantillas, donde los tipos de resultados del operador condicional pueden cambiar en /Zc:ternary y /permissive- . Una manera de resolver este problema es usar std::remove_reference en el tipo resultante.

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

Buscar nombres en dos fases

Cuando se establece la opción , el compilador analiza las definiciones de plantilla de función y clase, identificando los nombres dependientes y no dependientes que se usan en las plantillas según sea necesario para la búsqueda de nombres en dos /permissive- fases. En Visual Studio versión 15.3 de 2017, se realiza el análisis de dependencias de nombres. En concreto, los nombres no dependientes que no se declaran en el contexto de una definición de plantilla provocan un mensaje de diagnóstico según lo requerido por los estándares ISO de C++. En Visual Studio versión 15.7 de 2017, también se realiza el enlace de nombres no dependientes que requieren la busca dependiente de argumentos en el contexto de definición.

// 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 desea un comportamiento heredado para la búsqueda en dos fases, pero de lo contrario desea /permissive- un comportamiento, agregue la /Zc:twoPhase- opción .

Windows problemas de encabezado

La opción es demasiado estricta para las versiones de los kits de Windows Windows antes del SDK de /permissive- Fall Creators Update (10.0.16299.0) o la versión 1709 de Windows Driver Kit (WDK). Se recomienda actualizar a las versiones más recientes de los kits de Windows para usarlos en el código /permissive- Windows controlador de dispositivo.

Algunos archivos de encabezado en el SDK de actualización de Windows de abril de 2018 (10.0.17134.0), el SDK de fall Creators Update de Windows (10.0.16299.0) o el kit de controladores de Windows (WDK) 1709 siguen teniendo problemas que los hacen incompatibles con el uso de /permissive- . Para evitar estos problemas, se recomienda restringir el uso de estos encabezados solo a los archivos de código fuente que los requieran y quitar la opción al compilar esos archivos de código fuente /permissive- específicos.

Estos encabezados WRL de WinRT publicados en el SDK de actualización de abril de 2018 de Windows (10.0.17134.0) no están limpios con /permissive- . Para evitar estos problemas, no use /permissive- o use con cuando trabaje con estos /permissive-/Zc:twoPhase- encabezados:

  • Problemas en 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
    
  • Problema en 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'
    

Estos encabezados de modo de usuario publicados en el SDK de actualización de Windows abril de 2018 (10.0.17134.0) no están limpios con /permissive- . Para evitar estos problemas, no use /permissive- al trabajar con estos encabezados:

  • Problemas en 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
    
  • Problema en 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
    
  • Problemas en 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'
    

Estos problemas son específicos de los encabezados de modo de usuario en el SDK Windows Fall Creators Update (10.0.16299.0):

  • Problema en um/Query.h

    Cuando se usa el modificador del compilador, la estructura no se compila debido al /permissive-tagRESTRICTION miembro case(RTOr) '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;
    };
    

    Para solucionar este problema, compile archivos que incluyan Query.h sin la /permissive- opción .

  • Problema en um/cellularapi_oem.h

    Cuando se usa /permissive- el modificador del compilador, la declaración de reenvío enum UICCDATASTOREACCESSMODE de produce una advertencia:

    typedef enum UICCDATASTOREACCESSMODE UICCDATASTOREACCESSMODE; // C4471
    

    La declaración de reenvío de enumeración sin ámbito es una extensión de Microsoft. Para solucionar este problema, compile archivos que incluyan cellularapi_oem.h sin la opción o use la opción para silenciar la advertencia /permissive-/wd C4471.

  • Problema en um/omscript.h

    En C++03, una conversión de un literal de cadena a BSTR (que es una definición de tipo a "wchar_t *")) está en desuso, pero se permite. En C++11, ya no se permite la conversión.

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

    Para solucionar este problema, compile archivos que incluyan omscript.h sin la /permissive- opción o use en su /Zc:strictStrings- lugar.

Para establecer esta opción del compilador en el entorno de desarrollo de Visual Studio

En Visual Studio 2017, versión 15.5 y versiones posteriores, use este procedimiento:

  1. Abra el cuadro de diálogo Páginas de propiedades del proyecto.

  2. Seleccione la página de propiedades Propiedades deconfiguración del lenguaje C/C++.

  3. Cambie el valor de la propiedad Modo de conformidad a Sí (/permissive-). Elija Aceptar o Aplicar para guardar los cambios.

En versiones anteriores Visual Studio 2017, versión 15.5, use este procedimiento:

  1. Abra el cuadro de diálogo Páginas de propiedades del proyecto.

  2. Seleccione la página de propiedades Propiedades de configuraciónC /C++Línea de comandos.

  3. Escriba la opción del compilador /permissive- en el cuadro Opciones adicionales . Elija Aceptar o Aplicar para guardar los cambios.

Para establecer esta opción del compilador mediante programación

Vea también

Opciones del compilador de MSVC
Sintaxis de la línea de comandos del compilador MSVC