【问题标题】:What are canonical types in Clang?Clang 中的规范类型是什么?
【发布时间】:2014-10-03 13:28:36
【问题描述】:

我有一个基于 clang 的简单标头解析器,并且我从某个来源获取 typedef。

struct _poire {
int g;
tomate rouge;
};
typedef struct _poire kudamono;

解析后我有一个clang::TypedefDecl 然后我得到clang::TypedefDecl::getUnderlyingType() 的typedef 的clang::QualType

使用QualType 如果我使用getAsString 方法,我可以找到“struct _poire”std::string。这一切都好。

问题是,如果我尝试查看此类型是否为规范类型,使用QualType::isCanonical(),它会返回 false。

所以我尝试使用QualType::getCanonicalType().getAsString() 获取规范类型,它返回相同的字符串“struct _poire”。

根据类型 http://clang.llvm.org/docs/InternalsManual.html#canonical-types 的 clang 引用,我认为 isCanonical() 应该返回 不涉及 typedef 时为 true。

那么什么是真正的规范类型?

【问题讨论】:

    标签: c++ c clang llvm clang++


    【解决方案1】:

    经过进一步调查和 clang 邮件列表中的一个问题,我想我已经弄清楚了什么是规范类型。

    首先,重要的是不要专注于 QualType 以了解规范类型。看这个(代码/伪代码):

    源文件:

    typedef struct _poire kudamono; 
    

    clang 代码:

    QualType t = clang::TypedefDecl::getUnderlyingType()
    
    t.getAsString() // "struct _poire"
    t.isCanonical() // false
    t.getTypePtr()->getTypeClassName() // ElaboredType
    
    c = t.getCanonicalType()
    c.getAsString() // "struct _poire"
    c.isCanonical() // true
    c.getTypePtr()->getTypeClassName() // RecordType
    

    c 和 t 不是相同的 QualType,即使它们具有相同的字符串表示形式。 QualType 用于将限定符(“const”、“volatile”...)与 clang 类型相关联。有很多 Clang Types 类,因为 clang 需要跟踪用户指定的类型以进行诊断。(http://clang.llvm.org/docs/InternalsManual.html#the-type-class-and-its-subclasseshttp://clang.llvm.org/doxygen/classclang_1_1Type.html

    使用的 clang 类型在很大程度上取决于与源文件中的 C/C++ 类型相关的语法糖或修饰符。

    在上面的示例中,QualType t 与 ElaboratedType 相关联。此类型允许跟踪源代码中编写的类型名称。但是规范的 QualType 与 RecordType 相关联。

    另一个例子: 源文件:

    typedef struct _poire kudamono;
    typedef kudamono tabemono;
    

    clang 代码:

    QualType t = clang::TypedefDecl::getUnderlyingType()
    t.getAsString() // "kudamono"
    t.isCanonical() // false
    t.getTypePtr()->getTypeClassName() // TypedefType
    
    c = t.getCanonicalType()
    c.getAsString() // "struct _poire"
    c.isCanonical() // true
    c.getTypePtr()->getTypeClassName() // RecordType
    

    这里我们可以看到 typedef 的底层类型被记录为“kudamono”一个 TypedefType 而不是“struct _poire”一个 ElaboratedType。

    TypedefType“kudamono”的规范类型是 RecordType“struct _poire”。

    我从 clang 邮件列表 (http://article.gmane.org/gmane.comp.compilers.clang.devel/38371/match=canonical+type) 中获得的另一个示例:

    考虑:

    int (x);
    

    x 的类型不是 BuiltinType;它是一个 ParenType,其规范类型是 BuiltinType。并给出

    struct X { int n; };
    struct X x;
    

    x 的类型可能会表示为规范类型为 RecordType 的 ElaboratedType。

    因此,clang 中的规范类型是与任何语法糖或修饰符或 typedef(如 BuiltinType 或 RecordType)无关的类型类。其他类型的类型(如 ParentType、TypedefType 或 ElaboratedType)用于跟踪用户类型以进行诊断(错误消息...)。

    【讨论】:

      【解决方案2】:

      看来你提出了一个有趣的观点。我已经想通了,但由于我现在无法真正测试我的直觉,所以我不能 100% 确定。无论如何,这就是我会做的:

      如果我解析你的代码(带有一点扩展来声明一个 kudamono 变量),我可以从这里说:

      struct _poire {
          int g;
          char rouge; // tomate is probably one of your classes so I just changed the type of the field.
      };
      typedef struct _poire kudamono;
      
      int maFonction(){
          kudamono une_poire;
          return 0;
      }
      

      当 typedef 被解析时,产生的结果如下:

      -TypedefDecl 0x23b4620 <line:5:1, col:23> kudamono 'struct _poire':'struct _poire'

      当我声明kudamono 类型的变量时,这里是它的 AST-dump 下方:

      -VarDecl 0x2048040 <col:2, col:11> une_poire 'kudamono':'struct _poire'

      注意:您可以使用此命令行获取代码的 AST Dump,它可以非常方便地了解您的代码将如何被解析:

      clang -Xclang -ast-dump -std=c++11 -fsyntax-only test.cpp(如果你想编译一个,只需删除 -std=c++11 file_name.c 文件)

      现在,据我了解,我将在VarDeclTypedefDecl 之间进行比较:

      1°) 这个VarDecl 被命名为 une_poire 并且具有 kudamono 类型,它是 struct 类型的 typedef _poire

      2°) 这个TypedefDecl 被命名为 kudamono 并且具有 struct _poire 类型,它是 类型的 typedef结构体_poire

      所以,奇怪的部分就在这里。 struct _poire 被认为是来自 struct _poire 的 typedef。

      你会注意到我试图用通常的类型创建一个 typedef:

      typedef int numbers;

      这一次,AST-dump 产生:

      TypedefDecl 0x25d9680 <line:7:1, col:13> numbers 'int',所以我猜解析器可能对手工类型(通常是结构)有一些问题。

      我可以看到一种肮脏的方式来了解您的类型是否是规范的(没有得到误报或误报):

      检查 QualType 和规范 QualType 是否不相同

      我不知道Qualtype 之间的简单'=' 是否会产生误报或误报(因为我无法测试),但您仍然可以将类型名称与strcmp 进行比较

      所以,总结一下:

      • 您对规范类型的理解很好。
      • Clang 似乎对手工类型有一些问题,但使用普通类型的 Typedef 应该没问题(例如typedef int int32_t)。
      • 当你想知道一个类型是否规范时,你可以将类型的名称与规范类型的名称进行比较,但这很脏。在通常的类型上,isCanonical() 效果很好。

      【讨论】:

      • 我尝试比较 QualType 并且它们似乎不同,我尝试比较类型( QualType::getTypePtr() == QualType::getCanonicalType().getTypePtr() )但失败了也。但是对于“typedef int foo”,QualType 或 clang::Type 的比较返回 true。
      • 我不知道该命令才能进行 ast 转储。谢谢!
      • 是的,这是一个非常有用的命令。当我发现它时我也很高兴(因为我花了很多时间在 clang 命名空间中寻找合适的类)
      猜你喜欢
      • 2010-09-14
      • 1970-01-01
      • 1970-01-01
      • 2012-02-23
      • 2014-04-18
      • 2020-11-09
      • 2014-06-10
      • 2017-01-22
      • 2016-10-12
      相关资源
      最近更新 更多