0

I have the following c code test1.c:

double multiply(double x, double y) {
    return x * y * y;
}

int main(int argc, char const *argv[])
{
    double a;

    int b;

    float d;

    double x = 3.0;
    double y = 5.0;

    double z = multiply(x,y);

    return 0;
}

I'm trying to get the RecursiveASTVisitor to visit variable declarations (clang::VarDecl) by implementing bool VistVarDecl(clang::VarDecl *vardecl). However, the clang::VarDecl nodes are never visited even though I've managed to visit all the other nodes in the AST though. Moreover, using clang-query on test1.c I can match varDecl.

My RecursiveASTVistor is as follows:

struct MyASTVisitor : public clang::RecursiveASTVistor<MyASTVisitor> {

  bool VistVarDecl(clang::VarDecl *vardecl) {
     llvm::outs() << "Found a VarDecl";
  };

  bool VisitFunctionDecl(clang::FunctionDecl *decl) {
     llvm::outs() << "Found a FunctionDecl";
  };

  // other functions implemented similarly just to see if it visits properly
  bool VisitParmVarmDecl(clang::ParmVarDecl *paramvardecl);
  bool VisitCallExpr(clang::CallExpr *callexpr);
  bool VisitImplicitCastExpr(clang::ImplicitCastExpr *castexpr);
  bool VisitBinaryOperator(clang::BinaryOperator *bo);
  bool VisitDeclStmt(clang::DeclStmt *declstmt);
  bool VisitDeclRefExpr(clang::DeclRefExpr *declrefexpr);
  bool VisitFloatingLiteral(clang::FloatingLiteral *floatliteral);
};

struct MyASTConsumer : public clang::ASTConsumer {

  bool HandleTopLevelDecl(clang::DeclGroupRef DR) override {
    for (clang::DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b) {
        Visitor.TraverseDecl(*b);
     }
     return true;
  }
private: 
  MyASTVisitor Visitor;
};

Does anyone know the clang::VarDecl nodes are the only nodes that aren't visited by the RecursiveASTVisitor but are matched by clang-query?

The AST dump from clang is given below:

TranslationUnitDecl 0x7fba2300ce08 <<invalid sloc>> <invalid sloc>
|-TypedefDecl 0x7fba2300d6a0 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128'
| `-BuiltinType 0x7fba2300d3a0 '__int128'
|-TypedefDecl 0x7fba2300d710 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128'
| `-BuiltinType 0x7fba2300d3c0 'unsigned __int128'
|-TypedefDecl 0x7fba2300da18 <<invalid sloc>> <invalid sloc> implicit __NSConstantString 'struct __NSConstantString_tag'
| `-RecordType 0x7fba2300d7f0 'struct __NSConstantString_tag'
|   `-Record 0x7fba2300d768 '__NSConstantString_tag'
|-TypedefDecl 0x7fba2300dab0 <<invalid sloc>> <invalid sloc> implicit __builtin_ms_va_list 'char *'
| `-PointerType 0x7fba2300da70 'char *'
|   `-BuiltinType 0x7fba2300cea0 'char'
|-TypedefDecl 0x7fba2300dda8 <<invalid sloc>> <invalid sloc> implicit __builtin_va_list 'struct __va_list_tag [1]'
| `-ConstantArrayType 0x7fba2300dd50 'struct __va_list_tag [1]' 1
|   `-RecordType 0x7fba2300db90 'struct __va_list_tag'
|     `-Record 0x7fba2300db08 '__va_list_tag'
|-FunctionDecl 0x7fba22829370 <test4.c:2:1, line:4:1> line:2:8 used multiply 'double (double, double)'
| |-ParmVarDecl 0x7fba22829218 <col:17, col:24> col:24 used x 'double'
| |-ParmVarDecl 0x7fba22829298 <col:27, col:34> col:34 used y 'double'
| `-CompoundStmt 0x7fba22829560 <col:37, line:4:1>
|   `-ReturnStmt 0x7fba22829550 <line:3:2, col:17>
|     `-BinaryOperator 0x7fba22829530 <col:9, col:17> 'double' '*'
|       |-BinaryOperator 0x7fba228294d8 <col:9, col:13> 'double' '*'
|       | |-ImplicitCastExpr 0x7fba228294a8 <col:9> 'double' <LValueToRValue>
|       | | `-DeclRefExpr 0x7fba22829468 <col:9> 'double' lvalue ParmVar 0x7fba22829218 'x' 'double'
|       | `-ImplicitCastExpr 0x7fba228294c0 <col:13> 'double' <LValueToRValue>
|       |   `-DeclRefExpr 0x7fba22829488 <col:13> 'double' lvalue ParmVar 0x7fba22829298 'y' 'double'
|       `-ImplicitCastExpr 0x7fba22829518 <col:17> 'double' <LValueToRValue>
|         `-DeclRefExpr 0x7fba228294f8 <col:17> 'double' lvalue ParmVar 0x7fba22829298 'y' 'double'
`-FunctionDecl 0x7fba228297d0 <line:6:1, line:22:1> line:6:5 main 'int (int, const char **)'
  |-ParmVarDecl 0x7fba22829590 <col:10, col:14> col:14 argc 'int'
  |-ParmVarDecl 0x7fba228296b0 <col:20, col:37> col:32 argv 'const char **':'const char **'
  `-CompoundStmt 0x7fba22829da8 <line:7:1, line:22:1>
    |-DeclStmt 0x7fba22829928 <line:10:2, col:10>
    | `-VarDecl 0x7fba228298c0 <col:2, col:9> col:9 a 'double'
    |-DeclStmt 0x7fba228299c0 <line:12:2, col:7>
    | `-VarDecl 0x7fba22829958 <col:2, col:6> col:6 b 'int'
    |-DeclStmt 0x7fba22829a58 <line:14:2, col:9>
    | `-VarDecl 0x7fba228299f0 <col:2, col:8> col:8 d 'float'
    |-DeclStmt 0x7fba22829b10 <line:16:2, col:16>
    | `-VarDecl 0x7fba22829a88 <col:2, col:13> col:9 used x 'double' cinit
    |   `-FloatingLiteral 0x7fba22829af0 <col:13> 'double' 3.000000e+00
    |-DeclStmt 0x7fba22829bc8 <line:17:2, col:16>
    | `-VarDecl 0x7fba22829b40 <col:2, col:13> col:9 used y 'double' cinit
    |   `-FloatingLiteral 0x7fba22829ba8 <col:13> 'double' 5.000000e+00
    |-DeclStmt 0x7fba22829d60 <line:19:2, col:26>
    | `-VarDecl 0x7fba22829bf8 <col:2, col:25> col:9 z 'double' cinit
    |   `-CallExpr 0x7fba22829d00 <col:13, col:25> 'double'
    |     |-ImplicitCastExpr 0x7fba22829ce8 <col:13> 'double (*)(double, double)' <FunctionToPointerDecay>
    |     | `-DeclRefExpr 0x7fba22829c60 <col:13> 'double (double, double)' Function 0x7fba22829370 'multiply' 'double (double, double)'
    |     |-ImplicitCastExpr 0x7fba22829d30 <col:22> 'double' <LValueToRValue>
    |     | `-DeclRefExpr 0x7fba22829c80 <col:22> 'double' lvalue Var 0x7fba22829a88 'x' 'double'
    |     `-ImplicitCastExpr 0x7fba22829d48 <col:24> 'double' <LValueToRValue>
    |       `-DeclRefExpr 0x7fba22829ca0 <col:24> 'double' lvalue Var 0x7fba22829b40 'y' 'double'
    `-ReturnStmt 0x7fba22829d98 <line:21:2, col:9>
      `-IntegerLiteral 0x7fba22829d78 <col:9> 'int' 0
puhniste
  • 1
  • 1
  • 2
  • You'll get a better chance of getting the answer if you also include the code of the visitor :) – AlexDenisov Mar 16 '21 at 10:09
  • Thanks for the reminder, @AlexDenisov. – puhniste Mar 16 '21 at 20:32
  • Your `Visit*Decl` methods should return `true` explicitly. Without it, you are entering an area of undefined behavior and your program can do many unexpected things. In this specific case, I assume your program behaves as if you return `false`, which tells the ASTVisitor to stop traversing immediately. Try adding explicit `return true` to the end of each `Visit*` function. – AlexDenisov Mar 19 '21 at 07:48

1 Answers1

0

As noted in the comments, the problem here almost certainly is the failure to explicitly return true at the end of the Visit methods:

  bool VisitFunctionDecl(clang::FunctionDecl *decl) {
     llvm::outs() << "Found a FunctionDecl";
  };

Omitting the return causes undefined behavior. In practice, whatever is in the register used to convey return values may be used as-is, so if that register happens to contain 0, then false is effectively returned.

VisitFunctionDecl is called before its body is visited, and if false is returned, then the entire traversal is aborted, so it never gets to the VarDecl nodes.

Quoting the documentation:

Returning false from one of these overridden functions will abort the entire traversal.

Scott McPeak
  • 8,803
  • 2
  • 40
  • 79