How to access parsed C++11 attributes via clang to

2019-07-04 05:04发布

问题:

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?

回答1:

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.