首页 > 解决方案 > 为什么 clang++ 和 clang-check 会产生不同的 AST?

问题描述

我正在尝试分析来自这个小代码片段的 clang 的 AST。

struct Foo {
  Foo() = default;
  Foo(int num) : i(num) {}
  Foo(Foo &&other) {
    i = other.i;
    other.i = 0;
  }

  int i = 0;
};

Foo createAElidable(int i);

void func() { Foo foo = createAElidable(1234); }

Foo createAElidable(int i) { return Foo(i); }

运行“clang++ -Xclang -ast-dump example.cpp”给我这个输出:

TranslationUnitDecl #1 0x55c2ba1c07d8 <<invalid sloc>> <invalid sloc>
|-TypedefDecl #2 0x55c2ba1c10e0 <<invalid sloc>> <invalid sloc> implicit
| `-BuiltinType 0x55c2ba1c0d80 '__int128'
|-TypedefDecl #3 0x55c2ba1c1158 <<invalid sloc>> <invalid sloc> implicit
| `-BuiltinType 0x55c2ba1c0da0 'unsigned __int128'
|-TypedefDecl #9 0x55c2ba1c14f8 <<invalid sloc>> <invalid sloc> implicit
| `-RecordType 0x55c2ba1c1250 '__NSConstantString_tag'
|   `-CXXRecord 0x55c2ba1c11b8 '__NSConstantString_tag'
|-TypedefDecl #10 0x55c2ba1c15a0 <<invalid sloc>> <invalid sloc> implicit
| `-PointerType 0x55c2ba1c1560 'char *'
|   `-BuiltinType 0x55c2ba1c0880 'char'
|-TypedefDecl #16 0x55c2ba202118 <<invalid sloc>> <invalid sloc> implicit
| `-ConstantArrayType 0x55c2ba2020c0 '__va_list_tag [1]' 1
|   `-RecordType 0x55c2ba1c16a0 '__va_list_tag'
|     `-CXXRecord 0x55c2ba1c1600 '__va_list_tag'
|-CXXRecordDecl #17 0x55c2ba202178 <test27_copy_elision2.cpp:1:1, line:10:1> line:1:8 referenced
| |-CXXRecordDecl #18 0x55c2ba202298 <col:1, col:8> col:8 implicit referenced
| |-CXXConstructorDecl #19 0x55c2ba2023b8 <line:2:3, col:17> col:3 constexpr
| |-CXXConstructorDecl #21 0x55c2ba202548 <line:3:3, col:26> col:3 used
| | |-ParmVarDecl #20 0x55c2ba202480 <col:7, col:11> col:11 used
| | |-CXXCtorInitializer Field 0x55c2ba2027d8 'i' 'int'
| | | `-ImplicitCastExpr #32 0x55c2ba202c68 <col:20> 'int' <LValueToRValue>
| | |   `-DeclRefExpr #30 0x55c2ba202c18 <col:20> 'int' lvalue ParmVar 0x55c2ba202480 'num' 'int'
| | `-CompoundStmt 0x55c2ba202cb8 <col:25, col:26>
| |-CXXConstructorDecl #23 0x55c2ba202708 <line:4:3, line:7:3> line:4:3 used
| | |-ParmVarDecl #22 0x55c2ba202638 <col:7, col:13> col:13 used
| | |-CXXCtorInitializer Field 0x55c2ba2027d8 'i' 'int'
| | | `-CXXDefaultInitExpr #33 0x55c2ba202cc8 <col:3> 'int'
| | `-CompoundStmt 0x55c2ba202f18 <col:20, line:7:3>
| |   |-BinaryOperator #40 0x55c2ba202e40 <line:5:5, col:15> 'int' lvalue '='
| |   | |-MemberExpr #36 0x55c2ba202d88 <col:5> 'int' lvalue ->i 0x55c2ba2027d8
| |   | | `-CXXThisExpr #35 0x55c2ba202d70 <col:5> 'Foo *' implicit this
| |   | `-ImplicitCastExpr #39 0x55c2ba202e20 <col:9, col:15> 'int' <LValueToRValue>
| |   |   `-MemberExpr #38 0x55c2ba202de8 <col:9, col:15> 'int' lvalue .i 0x55c2ba2027d8
| |   |     `-DeclRefExpr #37 0x55c2ba202dc0 <col:9> 'Foo' lvalue ParmVar 0x55c2ba202638 'other' 'Foo &&'
| |   `-BinaryOperator #44 0x55c2ba202ef0 <line:6:5, col:15> 'int' lvalue '='
| |     |-MemberExpr #42 0x55c2ba202e90 <col:5, col:11> 'int' lvalue .i 0x55c2ba2027d8
| |     | `-DeclRefExpr #41 0x55c2ba202e68 <col:5> 'Foo' lvalue ParmVar 0x55c2ba202638 'other' 'Foo &&'
| |     `-IntegerLiteral #43 0x55c2ba202ec8 <col:15> 'int' 0
| |-FieldDecl #24 0x55c2ba2027d8 <line:9:3, col:11> col:7 referenced
| | `-IntegerLiteral #29 0x55c2ba202bf0 <col:11> 'int' 0
| |-CXXConstructorDecl #25 0x55c2ba202858 <line:1:8> col:8 implicit constexpr
| | `-ParmVarDecl #26 0x55c2ba202978 <col:8> col:8
| |-CXXMethodDecl #27 0x55c2ba202a18 <col:8> col:8 implicit
| | `-ParmVarDecl #28 0x55c2ba202b28 <col:8> col:8
| `-CXXDestructorDecl #55 0x55c2ba2313a8 <col:8> col:8 implicit referenced
|-FunctionDecl #46 0x55c2ba231048 <line:12:1, col:26> col:5 used
| `-ParmVarDecl #45 0x55c2ba230f80 <col:21, col:25> col:25
|-FunctionDecl #48 0x55c2ba231168 <line:14:1, col:48> col:6
| `-CompoundStmt 0x55c2ba231548 <col:13, col:48>
|   `-DeclStmt 0x55c2ba231530 <col:15, col:46>
|     `-VarDecl #49 0x55c2ba231220 <col:15, col:45> col:19
|       `-ExprWithCleanups #58 0x55c2ba231510 <col:25, col:45> 'Foo'
|         `-CXXConstructExpr #57 0x55c2ba2314d8 <col:25, col:45> 'Foo' 'void (Foo &&)' elidable
|           `-MaterializeTemporaryExpr #56 0x55c2ba2314b8 <col:25, col:45> 'Foo' xvalue
|             `-CallExpr #54 0x55c2ba231378 <col:25, col:45> 'Foo'
|               |-ImplicitCastExpr #53 0x55c2ba231358 <col:25> 'Foo (*)(int)' <FunctionToPointerDecay>
|               | `-DeclRefExpr #52 0x55c2ba231308 <col:25> 'Foo (int)' lvalue Function 0x55c2ba231048 'createAElidable' 'Foo (int)'
|               `-IntegerLiteral #51 0x55c2ba2312e0 <col:41> 'int' 1234
`-FunctionDecl #60 0x55c2ba231610 prev 0x55c2ba231048 <line:16:1, col:45> col:5 used
  |-ParmVarDecl #59 0x55c2ba231578 <col:21, col:25> col:25 used
  `-CompoundStmt 0x55c2ba231808 <col:28, col:45>
    `-ReturnStmt 0x55c2ba2317f8 <col:30, col:42>
      `-ExprWithCleanups #67 0x55c2ba2317d8 <col:37, col:42> 'Foo'
        `-CXXConstructExpr #66 0x55c2ba2317a0 <col:37, col:42> 'Foo' 'void (Foo &&)' elidable
          `-MaterializeTemporaryExpr #65 0x55c2ba231780 <col:37, col:42> 'Foo' xvalue
            `-CXXFunctionalCastExpr #64 0x55c2ba231750 <col:37, col:42> 'Foo' functional cast to struct Foo <ConstructorConversion>
              `-CXXConstructExpr #63 0x55c2ba231718 <col:37, col:42> 'Foo' 'void (int)'
                `-ImplicitCastExpr #62 0x55c2ba2316f8 <col:41> 'int' <LValueToRValue>
                  `-DeclRefExpr #61 0x55c2ba2316d0 <col:41> 'int' lvalue ParmVar 0x55c2ba231578 'i' 'int'

到目前为止,一切都很好。

Clang 的源代码还附带了他们重构 api 的示例。一种称为 clang-check,它还提供 AST 转储。

“clang-check --ast-dump”产生:

TranslationUnitDecl #1 0x563d3b96bfa8 <<invalid sloc>> <invalid sloc>
|-TypedefDecl #2 0x563d3b96c8b0 <<invalid sloc>> <invalid sloc> implicit
| `-BuiltinType 0x563d3b96c550 '__int128'
|-TypedefDecl #3 0x563d3b96c928 <<invalid sloc>> <invalid sloc> implicit
| `-BuiltinType 0x563d3b96c570 'unsigned __int128'
|-TypedefDecl #9 0x563d3b96ccc8 <<invalid sloc>> <invalid sloc> implicit
| `-RecordType 0x563d3b96ca20 '__NSConstantString_tag'
|   `-CXXRecord 0x563d3b96c988 '__NSConstantString_tag'
|-TypedefDecl #10 0x563d3b96cd70 <<invalid sloc>> <invalid sloc> implicit
| `-PointerType 0x563d3b96cd30 'char *'
|   `-BuiltinType 0x563d3b96c050 'char'
|-TypedefDecl #16 0x563d3b9ac468 <<invalid sloc>> <invalid sloc> implicit
| `-ConstantArrayType 0x563d3b9ac410 '__va_list_tag [1]' 1
|   `-RecordType 0x563d3b96ce70 '__va_list_tag'
|     `-CXXRecord 0x563d3b96cdd0 '__va_list_tag'
|-CXXRecordDecl #17 0x563d3b9ac4c8 </home/tyrdal/projects/emx-llvm/worktrees/mo_clang_12/test_clang_ccode/test27_copy_elision2.cpp:1:1, line:10:1> line:1:8 referenced
| |-CXXRecordDecl #18 0x563d3b9ac5e8 <col:1, col:8> col:8 implicit referenced
| |-CXXConstructorDecl #19 0x563d3b9ac708 <line:2:3, col:17> col:3 constexpr
| |-CXXConstructorDecl #21 0x563d3b9ac898 <line:3:3, col:26> col:3 used
| | |-ParmVarDecl #20 0x563d3b9ac7d0 <col:7, col:11> col:11 used
| | |-CXXCtorInitializer Field 0x563d3b9acb28 'i' 'int'
| | | `-ImplicitCastExpr #32 0x563d3b9acfb8 <col:20> 'int' <LValueToRValue>
| | |   `-DeclRefExpr #30 0x563d3b9acf68 <col:20> 'int' lvalue ParmVar 0x563d3b9ac7d0 'num' 'int'
| | `-CompoundStmt 0x563d3b9ad008 <col:25, col:26>
| |-CXXConstructorDecl #23 0x563d3b9aca58 <line:4:3, line:7:3> line:4:3
| | |-ParmVarDecl #22 0x563d3b9ac988 <col:7, col:13> col:13 used
| | |-CXXCtorInitializer Field 0x563d3b9acb28 'i' 'int'
| | | `-CXXDefaultInitExpr #33 0x563d3b9ad018 <col:3> 'int'
| | `-CompoundStmt 0x563d3b9ad268 <col:20, line:7:3>
| |   |-BinaryOperator #40 0x563d3b9ad190 <line:5:5, col:15> 'int' lvalue '='
| |   | |-MemberExpr #36 0x563d3b9ad0d8 <col:5> 'int' lvalue ->i 0x563d3b9acb28
| |   | | `-CXXThisExpr #35 0x563d3b9ad0c0 <col:5> 'Foo *' implicit this
| |   | `-ImplicitCastExpr #39 0x563d3b9ad170 <col:9, col:15> 'int' <LValueToRValue>
| |   |   `-MemberExpr #38 0x563d3b9ad138 <col:9, col:15> 'int' lvalue .i 0x563d3b9acb28
| |   |     `-DeclRefExpr #37 0x563d3b9ad110 <col:9> 'Foo' lvalue ParmVar 0x563d3b9ac988 'other' 'Foo &&'
| |   `-BinaryOperator #44 0x563d3b9ad240 <line:6:5, col:15> 'int' lvalue '='
| |     |-MemberExpr #42 0x563d3b9ad1e0 <col:5, col:11> 'int' lvalue .i 0x563d3b9acb28
| |     | `-DeclRefExpr #41 0x563d3b9ad1b8 <col:5> 'Foo' lvalue ParmVar 0x563d3b9ac988 'other' 'Foo &&'
| |     `-IntegerLiteral #43 0x563d3b9ad218 <col:15> 'int' 0
| |-FieldDecl #24 0x563d3b9acb28 <line:9:3, col:11> col:7 referenced
| | `-IntegerLiteral #29 0x563d3b9acf40 <col:11> 'int' 0
| |-CXXConstructorDecl #25 0x563d3b9acba8 <line:1:8> col:8 implicit constexpr
| | `-ParmVarDecl #26 0x563d3b9accc8 <col:8> col:8
| |-CXXMethodDecl #27 0x563d3b9acd68 <col:8> col:8 implicit
| | `-ParmVarDecl #28 0x563d3b9ace78 <col:8> col:8
| `-CXXDestructorDecl #55 0x563d3b9dd3a8 <col:8> col:8 implicit referenced
|-FunctionDecl #46 0x563d3b9dd048 <line:12:1, col:26> col:5 used
| `-ParmVarDecl #45 0x563d3b9dcf80 <col:21, col:25> col:25
|-FunctionDecl #48 0x563d3b9dd168 <line:14:1, col:48> col:6
| `-CompoundStmt 0x563d3b9dd4d0 <col:13, col:48>
|   `-DeclStmt 0x563d3b9dd4b8 <col:15, col:46>
|     `-VarDecl #49 0x563d3b9dd220 <col:15, col:45> col:19
|       `-CallExpr #54 0x563d3b9dd378 <col:25, col:45> 'Foo'
|         |-ImplicitCastExpr #53 0x563d3b9dd358 <col:25> 'Foo (*)(int)' <FunctionToPointerDecay>
|         | `-DeclRefExpr #52 0x563d3b9dd308 <col:25> 'Foo (int)' lvalue Function 0x563d3b9dd048 'createAElidable' 'Foo (int)'
|         `-IntegerLiteral #51 0x563d3b9dd2e0 <col:41> 'int' 1234
`-FunctionDecl #57 0x563d3b9dd598 prev 0x563d3b9dd048 <line:16:1, col:45> col:5 used
  |-ParmVarDecl #56 0x563d3b9dd500 <col:21, col:25> col:25 used
  `-CompoundStmt 0x563d3b9dd718 <col:28, col:45>
    `-ReturnStmt 0x563d3b9dd708 <col:30, col:42>
      `-CXXFunctionalCastExpr #61 0x563d3b9dd6d8 <col:37, col:42> 'Foo' functional cast to struct Foo <ConstructorConversion>
        `-CXXConstructExpr #60 0x563d3b9dd6a0 <col:37, col:42> 'Foo' 'void (int)'
          `-ImplicitCastExpr #59 0x563d3b9dd680 <col:41> 'int' <LValueToRValue>
            `-DeclRefExpr #58 0x563d3b9dd658 <col:41> 'int' lvalue ParmVar 0x563d3b9dd500 'i' 'int'

如您所见,此版本中没有 MaterializeTemporaraExpr 节点。为什么这两个工具会产生不同的 AST?我错过了一些选择吗?

我尝试使用(自编译)版本 10.0.1 和 12.0.0。两种情况下的行为相同。

PS:这只发生在Linux下。我现在在 Win10 下尝试,这两个工具生成相同的输出。

标签: c++clangabstract-syntax-tree

解决方案


推荐阅读