parameterized warning silencing macro trouble - c++

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.

Related

C++ ignoring warnings in a block with macro

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()
^~~~~

Why string concat macro doesn't work for this "+" case?

Short question:
Is it permitted to concat special signs such as +, - for the string concatenation macro ##? For example,
#define OP(var) operator##var
will OP(+) be expanded to operator+?
Exact problem:
#include "z3++.h"
#include <unordered_map>
namespace z3 {
z3::expr operator+(z3::expr const &, z3::expr const &);
}
typedef z3::expr (*MyOperatorTy)(z3::expr const &, z3::expr const &);
#define STR(var) #var
#define z3Op(var) static_cast<MyOperatorTy>(&z3::operator##var)
#define StrOpPair(var) \
{ STR(var), z3Op(var) }
void test() {
std::unordered_map<std::string, MyOperatorTy> strOpMap1{
{"+", static_cast<MyOperatorTy>(&z3::operator+)}}; // fine
std::unordered_map<std::string, MyOperatorTy> strOpMap2{StrOpPair(+)}; // error
}
For strOpMap2, using clang++ -c -std=c++11, it reports:
error: pasting formed 'operator+', an invalid preprocessing token
while using g++ -c -std=c++11, it gives:
error: pasting "operator" and "+" does not give a valid preprocessing token
By reading the manual by gcc I find it should be possible to concat, but why both compilers emit errors?
You can paste punctuation to form other punctuation, e.g.
#define PASTE(a,b) a##b
int main()
{
int i = 0;
i PASTE(+,+);
// i == 1 now
}
The ## operator is for producing a valid preprocessing token from other preprocessing tokens. The result of pasting must be a valid preprocessing token. So this is not valid:
PASTE(i,++)
because i++ is not a preprocessing token; it's two adjacent tokens i and ++.
The list of possible tokens is (N3797):
header-name
identifier
pp-number
character-literal
user-defined-character-literal
string-literal
user-defined-string-literal
preprocessing-op-or-punc
each non-white-space character that cannot be one of the above
Note: at the preprocessing stage, keyword does not exist; but after preprocessing, any identifiers which should be keyword are converted (semantically) into keywords. So you can build keywords by pasting shorter words.
In your code, operator+ is two tokens: operator and +. So you do not build it with ##; you just do one then the other.
#define OP(punc) operator punc

Forcing preprocessor error with macro

Is there a way that I can force a preprocessor macro in C++ to emit an error? What I would like to do is define a macro UNKNOWN. I'm writing some code for a robot, and I don't yet know where all of the electronics are being plugged in. I'd like to be able to define the ports in some header file, like
const int MOTOR_PORT = 1;
const int FAN_PORT = 2;
//etc.
However, when I reach a port that I don't yet know, I want to be able to write something like
const int LED_PORT = UNKNOWN;
In debug mode, UNKNOWN would just be defined to some arbitrary value, like 0. However, when compiling in release mode, I want it to throw an error when UNKNOWN is used, so that unassigned ports don't end up in the final release. I know I can use the #error directive to force an error, but can I do something similar in a macro?
I've seen a solution using static_assert, but I unfortunately can't use C++11 for this platform.
Since #error can't result from a macro expansion, you can ensure that the macro expands to something that must be diagnosed, like a syntax error.
For example:
#ifdef RELEASE
#define UNKNOWN #Invalid_use_of_UNKNOWN
#else
#define UNKNOWN 0
#endif
const int MOTOR_PORT = 1;
const int FAN_PORT = 2;
const int LED_PORT = UNKNOWN;
int main(void) {
int x = LED_PORT;
}
The # character isn't part of C's basic character set, so its appearance outside a comment, character constant, or string literal should always result in an error message. ($ would work, except that accepting $ in identifiers is a common extension. ` would probably also work, but # stands out better.)
I've defined the macro so it produces a reasonable error message with gcc:
c.c:9:1: error: stray ‘#’ in program
c.c:9:22: error: ‘Invalid_use_of_UNKNOWN’ undeclared here (not in a function)
and with clang:
c.c:9:22: error: expected expression
const int LED_PORT = UNKNOWN;
^
c.c:2:17: note: expanded from:
#define UNKNOWN #Invalid_use_of_UNKNOWN
^
1 error generated.
(There's a _Pragma operator corresponding to the #pragma directive. It would be nice if there were an _Error operator as well, but there isn't.)
Well, this does not produce a complier error message like #error, but would compile in debug and fail in release:
#ifdef _DEBUG
# define UNKNOWN 1
#else
# define UNKNOWN
#endif
const int port1 = UNKNOWN; // fail in release
You could make a division by zero which will throw a compiler error:
#define UNKNOWN 0/0
The sizeof operator cannot be applied to an incomplete type, so try this:
// Declared, but not defined anywhere.
struct illegal_use_of_unknown_macro;
#define UNKNOWN (sizeof (illegal_use_of_unknown_macro))

Why is clang parsing this as a user-defined literal?

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).

C++ Macro improperly terminated macro invocation

In C++ is there a mechanism to allow non terminated macros to be expressed?
This is a contrived example:
#define MACRO(x, y) x + y
#define MACROC1(x) MACRO(x,
#define MACROC2(y) y)
//...expecting 3
int foo = MACROC1(1) MACROC2(2);
I receive the error improperly terminated macro invocation from MSVC.
When I run cl -E file.cpp I see that the code below has been generated:
int c = 1 + 1 + 2);
In visual studio compilation fails with errors:
error C2059: syntax error : ')'
IntelliSense: improperly terminated macro invocation
I don't think this is possible. The C precompiler expands macros depth-first, so the MACROC1 will be full expanded before the MACROC2 is even considered. Then, it will find the MACRO with and incomplete argument list and throws an error.
Generally speaking, you should avoid defining macros that build other macro calls. Compilers tend not to agree in what those mean.
Your code would translate to :
int foo = MACRO(1, 2;
Which is wrong - it is an incomplete (improperly terminated) invocation of macro MACRO.