如何通过clang工具访问已解析的C ++ 11属性

jor*_*gen 5 attributes clang c++11

此答案表明,lang修订版165082应该保留AST中所有已解析的属性。

我首先认为这是指将保留所有属性,但是事实并非如此:

$ 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.
Run Code Online (Sandbox Code Playgroud)

在上面,请注意,与属性“ noreturn”相反,属性“ foo”确实已被忽略,并且在AST中不存在。

是将属性'foo'保留在AST中,还是将所有属性都保留在实际编译器中(如Attr.td等中所定义,如Clang内部手册中所述),才能保留在AST中?

Jeh*_*dad 5

只有当Clang知道了属性时,这些属性才保留在AST中,这是大多数GCC属性以及clang定义自身的属性。但是,您可以使用此链接中的提示来添加自己的属性。这使您可以定义任何新属性,然后按以下方式在ast中对其进行处理:例如,您从上面的链接中提取了代码行

__attribute__((annotate("async"))) uint c;
Run Code Online (Sandbox Code Playgroud)

然后,您可以在RecursiveASTVisitor实例中执行以下操作:

 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;                                                                                                                                                                                    
  }          
Run Code Online (Sandbox Code Playgroud)

第一个printf只打印“注释”,因为那是原始属性,为了获得要使用的值,我们从词法分析器中获取实际的标记作为字符串。

由于未创建新属性,因此仅获得了附加属性类型,但可以进一步挖掘并区分新创建的属性。虽然不如新创建的属性优雅(尽管可能需要更改itself代码本身),但仍然可以使用。