Description
I did this
Our project is currently using GCC 10.3 and as far as I know, this should be supported by curl 7.88.1. However, upon trying to upgrade curl from 7.86.0 to 7.88.1 we get some compilation errors in our existing code. The issue is known and appears to be fixed in GCC 12.1; #pragma
statements in macros can be reordered and this interferes with disabling -Wdeprecated-declarations
.
This is a rough simplification of what our code looks like, and a highly simplified version of the current logic within curl 7.88:
typedef enum {
CURLOPT_DEPRECATED __attribute__((__deprecated__)),
CURLOPT_OKAY,
} CURLoption;
int curl_easy_setopt(CURLoption val);
#define CURL_IGNORE_DEPRECATION(statement) \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \
statement \
_Pragma("GCC diagnostic pop")
static void __attribute__((__warning__("bad"))) __attribute__((__unused__)) __attribute__((__noinline__)) curl_warn(void) {
__asm__("");
}
#define curl_easy_setopt(_expr) \
__extension__ ({ \
CURLoption _internal_opt = (_expr); \
if (__builtin_constant_p(_internal_opt)) { \
CURL_IGNORE_DEPRECATION( \
if (_internal_opt == CURLOPT_DEPRECATED) { \
curl_warn(); \
} \
) \
} \
curl_easy_setopt(_internal_opt);\
})
#define SPRINGBOARD4(_expr) \
({ \
int ret = (_expr); \
ret; \
})
#define SPRINTBOARD3(_expr) \
({ \
if (SPRINGBOARD4(_expr) < 0) { \
return -1; \
} \
})
#define SPRINGBOARD2(_expr) \
SPRINTBOARD3(_expr)
#define SPRINGBOARD1(_expr) \
SPRINGBOARD4(_expr)
int test(void) {
SPRINGBOARD2(curl_easy_setopt(CURLOPT_OKAY));
if (SPRINGBOARD1(curl_easy_setopt(CURLOPT_OKAY)) < 0) {
return -1;
}
return 0;
}
Please try this code snippet out on godbolt.org under GCC < 12.1 The compiler output should look something like this:
<source>: In function 'test':
<source>:51:5: warning: 'CURLOPT_DEPRECATED' is deprecated [-Wdeprecated-declarations]
51 | SPRINGBOARD2(curl_easy_setopt(CURLOPT_OKAY));
| ^~~~~~~~~~~~
<source>:2:5: note: declared here
2 | CURLOPT_DEPRECATED __attribute__((__deprecated__)),
| ^~~~~~~~~~~~~~~~~~
<source>:52:1: error: expected expression before '#pragma'
52 | if (SPRINGBOARD1(curl_easy_setopt(CURLOPT_OKAY)) < 0) {
| ^
Compiler returned: 1
And the preprocessor output should look something like this:
int test(void) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#pragma GCC diagnostic pop
do { if (({ int ret = (__extension__ ({ CURLoption _internal_opt = (CURLOPT_OKAY); if (__builtin_constant_p(_internal_opt)) { if (_internal_opt == CURLOPT_DEPRECATED) { curl_warn(); } } curl_easy_setopt(_internal_opt); })); ret; }) < 0) { return -1; } } while (0);
if (
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#pragma GCC diagnostic pop
({ int ret = (__extension__ ({ CURLoption _internal_opt = (CURLOPT_OKAY); if (__builtin_constant_p(_internal_opt)) { if (_internal_opt == CURLOPT_DEPRECATED) { curl_warn(); } } curl_easy_setopt(_internal_opt); })); ret; }) < 0) {
return -1;
}
return 0;
}
Compilation will fail on every macro wrapping curl_easy_setopt
. Take a look at the preprocessor output for both to see the reason why; In GCC < 12.1 the #pragma
directives are placed in odd positions and depending on how the macro is structured we either get a deprecation warning on the unused deprecated CURLOPT, or the code gets completely mangled and we get the weird expected expression before '#pragma'
error.
If you try this same code block with >=12.1 the #pragmas are correctly placed and compilation is fine.
I expected the following
libcurl macros need to be rewritten to handle this case for GCC < 12.1
curl/libcurl version
7.88.1
operating system
Proprietary platform, however this is a compilation issue so that shouldn't matter.