I want to pass a raw string literals to [[deprecated(message)]] attribute as the message. The message is used again and again. So I want to avoid code repeat.
First, I tried to use static constexpr variable.
static constexpr auto str = R"(
Use this_func()
Description: ...
Parameter: ...
)";
[[deprecated(str)]]
void test1() {
}
I got the error "deprecated message is not a string". It seems that static constexpr variable isn't accepted by [[deprecated(message)]].
I tried to define the row string literals as preprocessor macro.
#define STR R"(
Use this_func()
Description: ...
Parameter: ...
)"
[[deprecated(STR)]]
void test2() {
}
It works as I expected as follows on clang++ 8.0.0.
prog.cc:38:5: warning: 'test2' is deprecated:
Use this_func()
Description: ...
Parameter: ...
[-Wdeprecated-declarations]
test2();
^
Demo: https://wandbox.org/permlink/gN4iOrul8Y0F76TZ
But g++ 9.2.0 outputs the compile error as follows:
prog.cc:19:13: error: unterminated raw string
19 | #define STR R"(
| ^
prog.cc:23:2: warning: missing terminating " character
23 | )"
| ^
https://wandbox.org/permlink/e62pQ2Dq9vTuG6Or
#define STR R"( \
Use this_func() \
Description: ... \
Parameter: ... \
)"
If I add backslashes on the tail of each line, no compile error occurred but output message is different from I expected as follows:
prog.cc:38:11: warning: 'void test2()' is deprecated: \\nUse this_func() \\nDescription: ... \\nParameter: ... \\n [-Wdeprecated-declarations]
I'm not sure which compiler works correctly.
Is there any way to pass the raw string literals variable/macro to [[deprecated]] attribute?
There is no such thing as a "raw string literal variable". There may be a variable which points to a string literal, but it is a variable, not the literal itself. The deprecated attribute does not take a C++ constant expression evaluating to a string. It takes a string literal: an actual token sequence.
So the most you can do is use a macro to contain your string literal. Of course, macros and raw string literals don't play nice together, since the raw string is supposed to consume the entire text. So the \ characters will act as both continuations for the macro and be part of the string.
Related
I built C parser from Lex/Flex & YACC/Bison grammars (1, 2) as:
$ flex c.l && yacc -d c.y && gcc lex.yy.c y.tab.c -o c
and then tested on this C code:
char* s = "xxx;
which is expected to produce missing terminating " character (or syntax error) diagnostics.
However, it doesn't:
$ ./c t1.c
char* s = xxx;
Why? How to fix it?
Note: The STRING_LITERAL is defined in lex specification as:
L?\"(\\.|[^\\"])*\" { count(); return(STRING_LITERAL); }
Here we see the [^\\"] part, which represents the "except the double-quote ", backslash , or new-line character" (C11, 6.4.5 String literals, 1) and the \\. part, which (incorrectly?) represents the escape-sequence (C11, 6.4.4.4 Character constants, 1). -- end note
UPD: Fix: The STRING_LITERAL is defined in lex specification as:
L?\"(\\.|[^\\"\n])*\" { count(); return(STRING_LITERAL); }
The lexer you link has a rule:
. { /* Add code to complain about unmatched characters */ }
so when it sees an unmatched ", it will silently ignore it. If you add code here to complain about the character, you'll see that.
If you want a syntax error, you could have this action just return *yytext;
Note that your STRING_LITERAL pattern will match strings that contain embedded newlines, so if you have a mismatched " in a larger program wity another string later, it will be recognized as a long string with embedded newlines. This will likely lead to poor error reporting, since the error would be reported after the bug string rather than where it starts, making it hard for a user to debug.
vector<string> foo(vector<string> s) { return s; }
assert(foo(vector<string>{"hello", "world"}) ==
vector<string>{"hello", "world"});
error: macro "assert" passed 2 arguments, but takes just 1
error: ‘assert’ was not declared in this scope
maybe define assert in gcc 11.1.0
# define assert(expr) \
(static_cast <bool> (expr) \
? void (0) \
: __assert_fail (#expr, __FILE__, __LINE__, __ASSERT_FUNCTION))
compiler flag is
-Wall -std=c++20
The preprocessor only has a primitive understanding of C++'s syntax, and in particular it sees any commas not enclosed in parentheses as argument separators. There are two commas in your assert call, and only one is enclosed in parentheses, so the macro thinks it's getting two arguments as follows
foo(vector<string>{"hello", "world"}) == vector<string>{"hello"
"world"});
Wrap the expression in parentheses to prevent this.
// Note: Double parens
assert((foo(vector<string>{"hello", "world"}) ==
vector<string>{"hello", "world"}));
I try to embed a code block through the use of macro like this:
#define RUN_CODE_SNIPPET(c) do {\
c\
} while(0);
where 'c' is a code block enclosed inside '{ }'
Here is how to use it
#include <stdio.h>
#define RUN_CODE_SNIPPET(c) do {\
c\
} while(0);
int main(int argc, char *argv[]) {
RUN_CODE_SNIPPET({
//const char *message = "World";
const char message[] = {'w', 'o', 'r', 'l', 'd', '\0'};
printf("%s\r\n", message);
});
return 0;
}
You can run it here here
But I get compiler error when I use the initializer list format
test.c: In function ‘main’:
test.c:13:4: error: macro "RUN_CODE_SNIPPET" passed 6 arguments, but takes just 1
});
^
test.c:9:3: error: ‘RUN_CODE_SNIPPET’ undeclared (first use in this function)
RUN_CODE_SNIPPET({
^~~~~~~~~~~~~~~~
test.c:9:3: note: each undeclared identifier is reported only once for each
function it appears in
Seems the compiler is taking each element in the initializer list as the argument to the macro itself. The string initializer works fine.
What is wrong here?
The commas in what you pass inside the parentheses are interpreted as macro argument separators and the macro is expecting just one argument.
There are two ways around the problem:
parenthesize the commas-containing argument, i.e., pass (a,b,c) instead of a,b,c (not applicable in your case because your argument is not an expression)
use variadic macro arguments (... -> __VA_ARGS__)
In other words:
#define RUN_CODE_SNIPPET(...) do { __VA_ARGS__; }while(0)
will work (including the semicolon at the end of the macro is not advisable -- for a function-like macro, you should generally be able to do if(X) MACRO(something); else {} and the semicolon would mess that up).
I am trying to do some code generation.
When I want to set type of returning value with the parameter compile fails.
Why compiler returns me error?
#define MODULE_GETTER(module_type, interface_type) \
public: \
static #interface_type * Instance##interface_type (void) \
{ \
return NULL;\
}
class MyModuleType :
public IMyModuleInterface
{
MODULE_GETTER(MyModuleType,IMyModuleInterface)
private:
...
};
When I change static #interface_type * into static int * or any other predefined type, code compiles without error.
What am I doing wrong?
Within a macro definition, # is the stringification operator, which wraps its operand in quotes to make a string literal; so the macro expands into
static "IMyModuleInterface" * InstanceIMyModuleInterface (void)
which is nonsense. Get rid of the rogue # and it should compile.
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).