Search code examples
c++cgcccompiler-warningssuppress-warnings

gcc c++ how to disable the `-Wno-error=permissive` error when `-fpermissive` and `-Werror` are both on? (Passing ptrs to R-values in C vs C++)


For this struct and function:

typedef struct data_s
{
    int i1;
    int i2;
} data_t;

void print_data_passed_by_ptr(const data_t *data)
{
    printf("  i1 = %i\n"
           "  i2 = %i\n\n",
           data->i1,
           data->i2);
}

the following works fine in C. As you can see below, I'm creating a data_t struct in-place and passing the address of it, as an R-value (meaning that it is not assigned to a variable), to the print_data_passed_by_ptr() function:

// Print R-value struct passed by ptr
print_data_passed_by_ptr(&(data_t){
    .i1 = 7,
    .i2 = 8,
});

My C build command is:

gcc -Wall -Wextra -Werror -O3 -std=c17 \
struct_pass_R_values_by_cpp_reference_and_ptr.c -o bin/a && bin/a

But, in C++ it fails with

error: taking address of temporary [-fpermissive]

My C++ build command is:

g++ -Wall -Wextra -Werror -O3 -std=c++17 \
struct_pass_R_values_by_cpp_reference_and_ptr.c -o bin/a && bin/a

So, I added -fpermissive to my C++ build command:

g++ -Wall -Wextra -Werror -O3 -std=c++17 -fpermissive \
struct_pass_R_values_by_cpp_reference_and_ptr.c -o bin/a && bin/a

and now the C++ build fails with this:

error: taking address of temporary [-Werror=permissive]

I tried turning off -Werror=permissive with -Wno-error=permissive (see here for that GCC documentation: https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html, and search the page for -Wno-error=), but that's not a valid option. New build cmd I attempted:

g++ -Wall -Wextra -Werror -O3 -std=c++17 -fpermissive -Wno-error=permissive \
struct_pass_R_values_by_cpp_reference_and_ptr.c -o bin/a && bin/a

...fails with:

cc1plus: error: -Werror=permissive: no option -Wpermissive

So, how do I solve this to force this C code to build in C++? Either suppressing the warning/error, OR providing some modification to the code other than the one shown just below are acceptable answers. I want the code to compile as C also, not just C++, in the end.

I know I can use "const reference" in C++ instead of ptr, like this, and that's great and all and it might answer somebody else's question, but that's not my question:

void print_data_passed_by_cpp_reference(const data_t& data)
{
    printf("  i1 = %i\n"
           "  i2 = %i\n\n",
           data.i1,
           data.i2);
}

// Print R-value struct passed by C++ reference
print_data_passed_by_cpp_reference({
    .i1 = 9,
    .i2 = 10,
});

I also know I can remove -Werror and keep -fpermissive to make it build, with warnings, like this:

eRCaGuy_hello_world/cpp$ g++ -Wall -Wextra -O3 -std=c++17 -fpermissive \
struct_pass_R_values_by_cpp_reference_and_ptr.c -o bin/a && bin/a
struct_pass_R_values_by_cpp_reference_and_ptr.c: In function ‘int main()’:
struct_pass_R_values_by_cpp_reference_and_ptr.c:87:5: warning: taking address of temporary [-fpermissive]
     });
     ^
Hello world.

  i1 = 7
  i2 = 8

  i1 = 9
  i2 = 10

...but I'd really like to keep -Werror on and make that warning go away.


Solution

  • How to automatically pass an R-value parameter into a function as a const ptr for C and as a const reference for C++

    (emphasis added to my original quote)

    So, how do I solve this to force this C code to build in C++? Either suppressing the warning/error, OR providing some modification to the code other than the one shown just below are acceptable answers. I want the code to compile as C also, not just C++, in the end.

    This works! It is one approach. If there are ways to disable the warning/error in gcc via command-line options I'd still like to know those though.

    This is pretty clever I think. It passes the R-value by const ptr for C and by const reference for C++ by using two separate definitions for the print_data() function and the DATA_T macro, depending on the language.

    #ifndef __cplusplus
    // For C
    void print_data(const data_t *data)
    {
        printf("  i1 = %i\n"
               "  i2 = %i\n\n",
               data->i1,
               data->i2);
    }
    #else
    // For C++
    void print_data(const data_t& data)
    {
        printf("  i1 = %i\n"
               "  i2 = %i\n\n",
               data.i1,
               data.i2);
    }
    #endif
    
    #ifndef __cplusplus
    // For C
    #define DATA_T &(data_t)
    #else
    // For C++
    #define DATA_T  // leave empty
    #endif
    

    Usage:

    
    // Print R-value struct passed by C++ reference, OR by C ptr, depending on
    // whether this code is compiled as C or C++
    print_data(DATA_T{
        .i1 = 9,
        .i2 = 10,
    });
    

    Build commands:

    # For C
    gcc -Wall -Wextra -Werror -O3 -std=c17 \
    struct_pass_R_values_by_cpp_reference_and_ptr.c -o bin/a && bin/a
    
    # For C++
    g++ -Wall -Wextra -Werror -O3 -std=c++17 \
    struct_pass_R_values_by_cpp_reference_and_ptr.c -o bin/a && bin/a
    

    See my experimental test code above inside struct_pass_R_values_by_cpp_reference_and_ptr.c in my eRCaGuy_hello_world repo.