I am using gcc 6.2 and want to ignore warnings in a macro. My idea was to do as in the following demo code.
typedef char aligned_char __attribute__((__aligned__));
// disable warning using #pragma at the beginning of the macro
// and enable it back at the end
#define DISABLE_WARNING() \
_Pragma ("GCC diagnostic push") \
_Pragma ("GCC diagnostic ignored \"-Wignored-attributes\"")
#define ENABLE_WARNING() \
_Pragma ("GCC diagnostic pop") \
#define MACRO() \
DISABLE_WARNING() \
A<aligned_char> a; \ << This will cause warning
a.print(); \
ENABLE_WARNING()
template <typename T>
class A {
public:
void print () {}
};
int main ()
{
MACRO()
}
So when the macro expands we have the pragma to ignore the warning also. But seems like I am missing something here. Could someone please explain why it doesnt work.
If I use -save-temps option, then I see the warning is ignored and the pragmas are proper
g++ -save-temps -Wall tmp.cpp
But if I compile without -save-temps
g++ -Wall tmp.cpp
I see the warning is not ignored.
tmp.cpp:14:19: warning: ignoring attributes on template argument ‘aligned_char {aka char}’ [-Wignored-attributes]
A<aligned_char> a; \
^
tmp.cpp:26:5: note: in expansion of macro ‘MACRO’
MACRO()
^~~~~
Related
The following code has been compiled with gcc-5.4.0 with no issues:
% gcc -W -Wall a.c
...
#include <stdio.h>
#include <stdarg.h>
static int debug_flag;
static void debug(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
#define DEBUG(...) \
do { \
if (debug_flag) { \
debug("DEBUG:"__VA_ARGS__); \
} \
} while(0)
int main(void)
{
int dummy = 10;
debug_flag = 1;
DEBUG("debug msg dummy=%d\n", dummy);
return 0;
}
However compiling this with g++ has interesting effects:
% g++ -W -Wall -std=c++11 a.c
a.c: In function ‘int main()’:
a.c:18:10: error: unable to find string literal operator ‘operator""__VA_ARGS__’ with ‘const char [8]’, ‘long unsigned int’ arguments
debug("DEBUG: "__VA_ARGS__); \
% g++ -W -Wall -std=c++0x
<same error>
% g++ -W -Wall -std=c++03
<no errors>
Changing debug("DEBUG:"__VA_ARGS__); to debug("DEBUG:" __VA_ARGS__); i.e. space before __VA_ARGS__ enables to compile with all three -std= options.
What is the reason for such behaviour? Thanks.
Since C++11 there is support for user-defined literals, which are literals, including string literals, immediately (without whitespace) followed by an identifier. A user-defined literal is considered a single preprocessor token. See https://en.cppreference.com/w/cpp/language/user_literal for details on their purpose.
Therefore "DEBUG:"__VA_ARGS__ is a single preprocessor token and it has no special meaning in a macro definition. The correct behavior is to simply place it unchanged into the macro expansion, where it then fails to compile as no user-defined literal operator for a __VA_ARG__ suffix was declared.
So GCC is correct to reject it as C++11 code.
This is one of the backwards-incompatible changes between C++03 and C++11 listed in the appendix of the C++11 standard draft N3337: https://timsong-cpp.github.io/cppwp/n3337/diff.cpp03.lex
Before C++11 the string literal (up to the closing ") would be its own preprocessor token and the following identifier a second preprocessor token, even without whitespace between them.
So GCC is also correct to accept it in C++03 mode. (-std=c++0x is the same as -std=c++11, C++0x was the placeholder name for C++11 when it was still in drafting)
It is also an incompatibility with C (in all revisions up to now) since C doesn't support user-defined literals either and considers the two parts of "DEBUG:"__VA_ARGS__ as two preprocessor tokens as well.
Therefore it is correct for GCC to accept it as C code as well (which is how the gcc command interprets .c files in contrast to g++ which treats them as C++).
To fix this add a whitespace between "DEBUG:" and __VA_ARGS__ as you suggested. That should make it compatible with all C and C++ revisions.
Here is the example code I used to reproduce this error:
#include <iostream>
#define TEST_2_ARG_MACRO_OVERLOAD(_1,_2,FUNC_NAME,...) FUNC_NAME
#define TEST_HELLO_IMPL(condition) do{ \
if(!(condition)) {\
std::cout << "hello!" << std::endl; \
}\
} while(0)
#define TEST_HELLO_MESSAGE_IMPL(condition, message) do{ \
if(!(condition)) {\
std::cout << "hello" << message << std::endl; \
}\
} while(0)
//Runs during runtime and debug
#define TEST_HELLO(...) TEST_2_ARG_MACRO_OVERLOAD(__VA_ARGS__, TEST_HELLO_MESSAGE_IMPL, TEST_HELLO_IMPL)(__VA_ARGS__)
int main()
{
auto x = 3 * (3);
TEST_HELLO(x >= 3);
}
In godbolt with GCC x86-64 8.2 using:
-std=c++14 -Wall -Wextra -Wshadow -Wnon-virtual-dtor -Wpedantic -Werror
as arguments I get the following error:
<source>:24:22: error: ISO C++11 requires at least one argument for the "..." in a variadic macro [-Werror]
TEST_HELLO(x >= 3);
^
cc1plus: all warnings being treated as errors
Compiler returned: 1
Yet there is clearly at least one argument in the macro. Now I know this compiles when I don't enable this warning, and when I don't enable this warning as an error, but for other reasons I want to keep these compiler flags (or at least keep the same results).
Why does GCC claim that I've passed zero arguments when I have not?
The problem is actually with TEST_2_ARG_MACRO_OVERLOAD, the error message is slightly misleading.
The macro takes 3 arguments and ... , in ISO C++ that means you must pass at least 4 arguments but in fact you only pass 3. (Ref: C++17 [cpp.replace]/4)
The TEST_HELLO expands to TEST_2_ARG_MACRO_OVERLOAD(x >= 3, TEST_HELLO_MESSAGE_IMPL, TEST_HELLO_IMPL)(x >= 3) .
The following doesn't compile:
#define SUPPRESS(w) _Pragma("GCC diagnostic ignored " ## w)
SUPPRESS("-Wuseless-cast")
int main() {
int a = (int)4;
return a;
}
Here's the error:
error: pasting ""GCC diagnostic ignored "" and ""-Wuseless-cast"" does not give a valid preprocessing token
How can I get it to work?
The thing is that _Pragma wants to have an escaped string-literal like so
_Pragma("GCC diagnostic ignored \"-Wuseless-cast\"")
So the trick is to add another layer of stringyfication between the call of SUPPRESS and the call of _Pragma like below
#define xSUPPRESS(w) _Pragma(#w)
#define SUPPRESS(w) xSUPPRESS(GCC diagnostic ignored w)
SUPPRESS("-Wuseless-cast")
See it here in action.
using g++ and compiling with -Waggregate-return
#define DOCTEST_CHECK(expr) \
do { \
_Pragma("GCC diagnostic push"); \
_Pragma("GCC diagnostic ignored \"-Waggregate-return\"");\
if(Result failed = (ExpressionDecomposer() << expr)) \
printf("%s\n", failed.m_decomposition.c_str()); \
_Pragma("GCC diagnostic pop"); \
} while(false)
DOCTEST_CHECK(true == false); // produces warnings
but the unrolled by hand version does not produce any warnings:
do {
_Pragma("GCC diagnostic push");
_Pragma("GCC diagnostic ignored \"-Waggregate-return\"");
if(Result failed = (ExpressionDecomposer() << true == false))
printf("%s\n", failed.m_decomposition.c_str());
_Pragma("GCC diagnostic pop");
} while(false);
Shouldn't the behavior be the same?
I don't think the Result and ExpressionDecomposer types matter - just classes.
I'm trying to get expression decomposition working like here (things have been renamed a bit).
EDIT: >> here << is a live demo of the problem using the lest library
My question is: why? how can I be warning free in the first case using the macro? I cannot afford silencing the warning globally.
These bugs look relevant:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55578
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69543
So it might have to do with line number comparisons, or some similar issue within the parser, and it might be fixed in some future version.
You could try :
#define DOCTEST_CHECK(expr) \
do { \
_Pragma("GCC diagnostic push"); \
_Pragma("GCC diagnostic ignored \"-Waggregate-return\"");\
if(Result failed = (ExpressionDecomposer() << (expr))) \
printf("%s\n", failed.m_decomposition.c_str()); \
_Pragma("GCC diagnostic pop"); \
} while(false)
I have some code I am maintaining that I've started compiling under clang 3.3.
When compiling with "-std=c++11", clang generates an error (given below). I've distilled the offending code to the following:
#include <stdio.h>
#define DBG_PRT(__format, ...) \
printf("%s:%d:%s: "__format, __FILE__, \
__LINE__, __FUNCTION__, ## __VA_ARGS__)
int main()
{
DBG_PRT("%s\n", "Hi");
}
This is clang's output:
test.cpp:10:5: error: no matching literal operator for call to
'operator "" __format' with arguments of types 'const char *' and
'unsigned int'
DBG_PRT("%s\n", "Hi");
^ test.cpp:4:29: note: expanded from macro 'DBG_PRT'
printf("%s:%d:%s: "__format, __FILE__, \
^ 1 error generated.
Without spaces between the string literal and "__format", it doesn't seem like the preprocessor should be able to expand __format. It clearly is, though, when not specifying -std=c++11. G++ 4.4.7 (with and without -std=c++0x) compiles just fine.
Is there an error with the compiler?
This is because ""_ is a syntax for user-defined string literals. Put a space in between to have the old behavior (concatenate literals). GCC works fine because 4.4.7 does not implement user defined literals (it appeared in version 4.7).
Also, as #Fred have pointed out, try to avoid using reserved identifier (double underscore).