How to access parsed C++11 attributes via clang tooling - c++11

This answer suggests that clang post revision 165082 should retain all parsed attributes in the AST.
I first took this to mean that all attributes would be retained, but this does not appear to be the case:
$ clang++ -v
Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin13.0.0
Thread model: posix
$ cat att.cpp
void f [[noreturn, foo]] () {}
$ clang++ att.cpp -Xclang -ast-dump -fsyntax-only -std=c++11
att.cpp:1:20: warning: unknown attribute 'foo' ignored [-Wattributes]
void f [[noreturn, foo]] () {}
^
att.cpp:1:30: warning: function declared 'noreturn' should not return [-Winvalid-noreturn]
void f [[noreturn, foo]] () {}
^
TranslationUnitDecl 0x102021cd0 <<invalid sloc>>
|-TypedefDecl 0x102022210 <<invalid sloc>> __int128_t '__int128'
|-TypedefDecl 0x102022270 <<invalid sloc>> __uint128_t 'unsigned __int128'
|-TypedefDecl 0x102022630 <<invalid sloc>> __builtin_va_list '__va_list_tag [1]'
`-FunctionDecl 0x1020226d0 <att.cpp:1:1, col:30> f 'void (void)'
|-CompoundStmt 0x1020227b0 <col:29, col:30>
`-CXX11NoReturnAttr 0x102022770 <col:10>
2 warnings generated.
In the above, note that attribute 'foo' has indeed been ignored, and is not present in the AST, as opposed to the attribute 'noreturn'.
Will attribute 'foo' be retained in the AST at some point, or will all attributes have to be part of the actual compiler (defined in Attr.td etc., as described in the Clang Internals Manual) to be retained in the AST?

The attributes are only retained in the AST if they are already known by Clang, which are most of the GCC attribs and the ones that clang defines itself. However you can(sort of) add your own attribs using the hints from this link. This enables you to define any new attribute and then process it in the ast in the following manner:
For example you took the line of code from the above link
__attribute__((annotate("async"))) uint c;
Then in your RecursiveASTVisitor instantiation you can do as follows:
bool MyRecursiveASTVisitor::VisitVarDecl(VarDecl* v)
{
v->dump();
if(v->hasAttrs()){
clang::AttrVec vec = v->getAttrs();
printf("%s\n",vec[0]->getSpelling());
printf("%s\n", Lexer::getSourceText(
CharSourceRange::getTokenRange(
vec[0]->getRange()),
compiler.getSourceManager(),
langOpts).str().c_str());
}
return true;
}
The first printf only prints the "annotate" since that is the original attribute, to get the value which is of interest to use we get the actual token from the lexer as a string.
Since we did not create a new attribute we only get the append attribute type but we can dig further and distinguish our newly created attribute. Not as elegant as a newly created attribute ( which though possible needs changing clang code itself) but still works.

Related

How to query GCC warnings for C++?

GCC allows querying available warning flags specific for C++ language with the syntax:
g++ -Q --help=warning,c++
Adding warning flags to the call includes them in the result:
g++ -Wall -Q --help=warning,c++
However, it seems the call is done from the C point of view and I don't know how to do it from the C++ point of view. If the call includes C++-only warning, like:
g++ -Wnon-virtual-dtor -Q --help=warning,c++
the output contains a message:
cc1: warning: command line option ‘-Wnon-virtual-dtor’ is valid for C++/ObjC++ but not for C
and still shows the warning as disabled:
-Wnon-virtual-dtor [disabled]
Note, that this happens regardless of whether the call is done using g++ or gcc.
The same with C-only -Wbad-function-cast behaves in an expected way:
gcc -Wbad-function-cast -Q --help=warning,c
There is no extra message and reported warning status changes between [disabled] and [enabled]. Again, regardless of whether g++ or gcc is used.
I'm using GCC version 7.3.0. Although the issue seems to apply to many if not all versions. It can be observed through Compiler Explorer.
So, is there a way to do this query with respect to given language?
Yes, your observations are correct.
Probably this is not the intended behavior, and if you care about this feature, then I suggest reporting it upstream.
Note that this works, however:
touch 1.cc
g++ -Wnon-virtual-dtor -Q --help=warning,c++ 1.cc
I.e. if there's an input file with a proper extension, then the correct compiler proper executable is invoked: cc1plus, not cc1. The latter is the default if no input files are present. I did some quick debugging, and here's how that happens:
// gcc.c:
driver::do_spec_on_infiles () const
{
...
for (i = 0; (int) i < n_infiles; i++)
{
...
/* Figure out which compiler from the file's suffix. */
input_file_compiler
= lookup_compiler (infiles[i].name, input_filename_length,
infiles[i].language);
if (input_file_compiler)
{
...
value = do_spec (input_file_compiler->spec);
And input_file_compiler at that point is the C compiler, because
p n_infiles
$9 = 1
(gdb) p infiles[0]
$10 = {name = 0x4cbfb0 "help-dummy", language = 0x4cbfae "c", incompiler = 0x58a920, compiled = false, preprocessed = false}
Here's how the dummy file got created (function process_command in the same file):
if (n_infiles == 0
&& (print_subprocess_help || print_help_list || print_version))
{
/* Create a dummy input file, so that we can pass
the help option on to the various sub-processes. */
add_infile ("help-dummy", "c");
}

Vala error "unknown type name" using enum from camel

I am writing this code in Vala, using Camel
using Camel;
[...]
MimeParser par = new MimeParser();
[...]
par.push_state( MimeParserState.MULTIPART, boundary );
I downloaded the camel-1.2.vapi from github vala-girs (this link), put it in a vapi subdirectory and compiled with
valac --vapidir=vapi --includedir=/usr/include/evolution-data-server/camel --pkg camel-1.2 --pkg posix --target-glib=2.32 -o prog prog.vala -X -lcamel-1.2
Compiling I get this error:
error: unknown type name "CamelMimeParserState"
const gchar* camel_mime_parser_state_to_string (CamelMimeParserState self);
Looking the C output code I see that the CamelMimeParserState type is used several times but it is never defined. It should be a simple enum because the camel-1.2.vapi file says:
[CCode (cheader_filename = "camel/camel.h", cprefix = "CAMEL_MIME_PARSER_STATE_", has_type_id = false)]
public enum MimeParserState {
INITIAL,
PRE_FROM,
FROM,
HEADER,
BODY,
MULTIPART,
MESSAGE,
PART,
END,
EOF,
PRE_FROM_END,
FROM_END,
HEADER_END,
BODY_END,
MULTIPART_END,
MESSAGE_END
}
So why doesn't the C output code simply use an enum as the vapi file says (described by cprefix CAMEL_MIME_PARSER_STATE_)?
Is there an error in the .vapi file?
I found the solution. The vapi file is wrong because the cname field is missing. Changing the vapi file adding this cname="camel_mime_parser_state_t":
[CCode (cheader_filename = "camel/camel.h", cname="camel_mime_parser_state_t", cprefix = "CAMEL_MIME_PARSER_STATE_", has_type_id = false)]
public enum MimeParserState {
INITIAL,
[...]
works correctly.

Crypto++ AutoSeededRandomPool copy constructor implicitly deleted

My question is about a crypto++ constructor and why it is in the state of being "implicitly deleted" even though it follows the examples provided in the documentation.
I am trying to go off of the code provided by the example on Crypto++'s documentation to create a digital signature key pair, but I am having trouble calling the constructor for AutoSeededRandomPool objects.
Here is the command I am calling to the terminal:
g++ -I /usr/local/include/ -l cryptopp -std=c++11 -c -o build/account.o src/account.cpp
I am getting the following error:
error: call to implicitly-deleted copy constructor of 'CryptoPP::AutoSeededRandomPool',
note: copy constructor of 'AutoSeededRandomPool' is implicitly deleted because base
class 'CryptoPP::RandomPool' has a deleted copy constructor
Additionally, I get this unusual message:
clang: warning: -lcryptopp: 'linker' input unused [-Wunused-command-line-argument]
Here is are the files I use to generate the public/private key pair. They pretty much follow the example:
DSA::PrivateKey create_private_key(AutoSeededRandomPool rng) {
DSA::PrivateKey private_Key;
private_Key.GenerateRandomWithKeySize(rng, 1024);
return private_Key;
}
DSA::PublicKey create_public_key(DSA::PrivateKey private_key, AutoSeededRandomPool rng) {
DSA::PublicKey public_Key;
public_Key.AssignFrom(private_key);
if (!private_key.Validate(rng, 3) || !public_Key.Validate(rng, 3))
{
throw std::runtime_error("DSA key generation failed");
}
return public_Key;
}
I declare and initialize the AutoSeededRandomPool object in a constructor as follows:
account::account() {
balance = 0;
AutoSeededRandomPool rng;
private_key = utils::create_private_key(rng);
public_key = utils::create_public_key(private_key, rng);
}
I have linked in the libraries necessary for this, and I am linking them in when I call g++. Additionally, if anyone knows if there are any more detailed examples of Crypto++ code, those resources would be greatly appreciated.
g++ -I /usr/local/include/ -l cryptopp -std=c++11 -c -o build/account.o src/account.cpp
clang: warning: -lcryptopp: 'linker' input unused
Try:
g++ ... src/account.cpp -c -o build/account.o
Omit -l cryptopp. It is only needed during link.
DSA::PrivateKey create_private_key(AutoSeededRandomPool rng) {
DSA::PrivateKey private_Key;
private_Key.GenerateRandomWithKeySize(rng, 1024);
return private_Key;
}
error: call to implicitly-deleted copy constructor of
'CryptoPP::AutoSeededRandomPool', note: copy constructor of
'AutoSeededRandomPool' is implicitly deleted because base class
'CryptoPP::RandomPool' has a deleted copy constructor
Pass rng by reference:
DSA::PrivateKey create_private_key(AutoSeededRandomPool& rng) {
...
}
Do it in both create_private_key and create_public_key.
The reason is, AutoSeededRandomPool base class is RandomPool, and RandomPool base class is NotCopyable. NotCopyable hides copy and assignment by making them private. I guess that's where the "implicit" part comes from the compiler error.
class RandomPool : public RandomNumberGenerator, public NotCopyable
{
...
}
IF you don't want to pass by reference, then create one locally. There are certain reasons why you want to do this when generating a private key. See Cryptography Engineering: Design Principles and Practical Applications for more details.
DSA::PrivateKey create_private_key() {
AutoSeededRandomPool rng;
DSA::PrivateKey private_Key;
private_Key.GenerateRandomWithKeySize(rng, 1024);
return private_Key;
}
Related, when you link, place -lcryptopp at the end of the command. Something like:
g++ -o myprog -std=c++11 build/account.o build/some-other-object.o -lcryptopp -pthread
Order matters because LD is a single pass linker. Libraries always go at the end. You can work around it with options like -( and --start-group, but its easy to remember to place libraries at the end.
Some more of the C++11 backstory is, when you experience copy constructor implicitly deleted, you usually define one in your class. See, for example, Use of deleted function error.
However, in the case of AutoSeededRandomPool, we don't want them copied for several reasons. The Crypto++ Algorithm class, which is a base class of AutoSeededRandomPool, has a Clone. However, we don't want the generator cloned, either. Again, see Cryptography Engineering: Design Principles and Practical Applications.

how to fix wrong stack alignment with Eigen library under Workbench3.0 (vxworks 6.6 IDE)

I am using Eigen(3.2.0) Library under Workbench3.0 (vxworks 6.6). The compiler in this distribution is GCC version 4.1.2.
Language : c++; Operating System: winXP
the problem code is as followed:
Eigen::Matrix3d mOrigin;
/* initial mOrigin */
...
Eigen::Quaterniond qOrigin(mOrigin);
I debuged the program and found that when it runs :
Eigen::Quaterniond qOrigin(mOrigin);
it comes out the assertion and prints:
assertion failed: (reinterpret_cast(array) & 0xf) == 0 && "this assertion is explained here: " "http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" " **** READ THIS WEB PAGE !!
! ****" in function Eigen::internal::plain_array::plain_array() [with T = double, int Size = 4, int MatrixOrArrayOptions = 0] at C:/WindRiver-GPPVE-3.6-IA-Eval/vxworks-6.6/target/h/Eigen/src/Core/DenseStorage.h:78
it said, fixed-size vectorizable Eigen objects must absolutely be created at 16-byte-aligned locations, otherwise SIMD instructions adressing them will crash. And that is why the assertion arises.
I think the problem is:
Compiler making a wrong assumption on stack alignment
http://eigen.tuxfamily.org/dox-devel/group__TopicWrongStackAlignment.html
it said, It appears that this was a GCC bug that has been fixed in GCC 4.5. If you hit this issue, please upgrade to GCC 4.5 and report to us, so we can update this page.
However, GCC is the intergation compiler of Workbench and I don't know how to upgrade it.
And I think I have tested the Local Solution and Global Solution, but they don't work.
Local Solution:
add "__attribute__((force_align_arg_pointer))"
class Interpolation : public InterpMath/*,public Colleague*/
{
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
...
__attribute__((force_align_arg_pointer)) ErrorID LineInterp(
const Position_MCS_rad &targetPoint,
const Position_MCS_rad &originPoint,
const Position_ACS_rad &originACS,
double Ts, double maxVel, double maxAcc,
double maxDecel, double maxJerk,
N_AxisSeqPtr &nAglSeqPtr, GrpTcpSeq *pGrpTcp = NULL)
{
Eigen::Matrix3d mOrigin;
/* initial mOrigin */
...
Eigen::Quaterniond qOrigin(mOrigin);
}
}
warning: 'force_align_arg_pointer' attribute directive ignored
Global Solution:
add compile option -mstackrealign
ccpentium -g -mtune=pentium4 -march=pentium4 -ansi -Wall -MD -MP -Xlinker -mstackrealign -IC:/WindRiver-GPPVE-3.6-IA-Eval/vxworks-6.6/target/h -IC:/WindRiver-GPPVE-3.6-IA-Eval/vxworks-6.6/target/h/wrn/coreip -IC:/WindRiver-GPPVE-3.6-IA-Eval/workspace/RobotInterface_2_2/h -DCPU=PENTIUM4 -DTOOL_FAMILY=gnu -DTOOL=gnu -D_WRS_KERNEL -o
So how can I upgrade the intergration compiler to gcc 4.5 or newer, or whether there is other solution to fix this problem ?
Thanks for reading and help.

Clang does not compile a g++ project

When trying to compile a g++ project with the clang compiler, there is a strange error showing up.
Here is the snippet of the source file:
std::set<TTransportNetworkId> l_transportNetworkIds;
SelectionResultContainer l_searchResult = p_repo.rootMoc() / LnAny("LNBTS") / LnAny("LNMME");
BOOST_FOREACH(const SelectionResult & l_lnmmeSR, l_searchResult)
{
const MoLnmme & l_lnmme = l_lnmmeSR;
l_transportNetworkIds.insert(*l_lnmme.transportNwId);
}
The error message is:
conditional expression is ambiguous; 'rvalue_probe<Rrom::DataRep::SelectionResultContainer>' can be converted to 'Rrom::DataRep::SelectionResultContainer' and vice versa
BOOST_FOREACH(const SelectionResult & l_lnmmeSR, l_searchResult)
Conditions are:
The file compiles fine with gcc_4.3.2
clang in version 3.2 throws the above error
Already tried to include the latest boost library which results in the same error
My guess is that clang handles rvalue conditions differently than this gcc version does.
clang is supposed to be a drop-in-replacement for gcc, so how can one get rid of this error without touching the source file?
Are there any options in clang which somehow disables these kind of errors?!
UPDATE:
I could create an example source file, which you can reproduce for yourself:
#include <vector>
#include <boost/foreach.hpp>
class A : public std::vector<int>
{
public:
template <class T>
operator const T &() const;
};
void foo(){
A colA;
int b = 1;
BOOST_FOREACH(b, colA)
{
;
}
}
When compiled with clang 3.2 the above error is raised, with some additional insights to where exactly the error occurs:
error: conditional expression is ambiguous; 'rvalue_probe<A>' can be converted to 'A' and vice versa BOOST_FOREACH(b, colA)
expanded from macro 'BOOST_FOREACH' f (boost::foreach_detail_::auto_any_t BOOST_FOREACH_ID(_foreach_col) = BOOST_FOREACH_CONTAIN(COL))
expanded from macro 'BOOST_FOREACH_CONTAIN' BOOST_FOREACH_EVALUATE(COL)
expanded from macro 'BOOST_FOREACH_EVALUATE' (true ? boost::foreach_detail_::make_probe((COL), BOOST_FOREACH_ID(_foreach_is_rvalue)) : (COL))
This code is compiled without errors with gcc_4.7.2.
Any ideas why the two compilers behave differently?
I found the solution in this document, see http://www.boost.org/doc/libs/1_43_0/boost/foreach.hpp
Snippet:
// Some compilers do not correctly implement the lvalue/rvalue conversion
// rules of the ternary conditional operator.
# if defined(BOOST_FOREACH_NO_RVALUE_DETECTION)
So, when providing a -DBOOST_FOREACH_NO_RVALUE_DETECTION definition option to clang, the error disappears.
Still the question remains whether gcc or clang is right or wrong on this point.

Resources