Gabriel Staples
Gabriel Staples

Reputation: 52737

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.

Upvotes: 3

Views: 3665

Answers (1)

Gabriel Staples
Gabriel Staples

Reputation: 52737

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.

Upvotes: 0

Related Questions