Clang中的规范类型是什么?

What are canonical types in Clang?

本文关键字:类型 是什么 范类型 Clang      更新时间:2023-10-16

我有一个基于clang的简单头解析器,我从一些来源获得类型定义。

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

解析后,我有一个clang::TypedefDecl,然后我得到clang::TypedefDecl::getUnderlyingType()类型定义的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。

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

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

首先,重要的是不要专注于QualType来理解Canonical Type。看这个(代码/伪代码):

源文件:

typedef struct _poire kudamono; 

clang code:

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-subclasses and http://clang.llvm.org/doxygen/classclang_1_1Type.html)

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

在上面的例子中,QualType t与一个detailatedtype相关联。这种类型允许跟踪源代码中所写的类型名称。但是规范的QualType与RecordType相关联。

另一个例子:源文件:

typedef struct _poire kudamono;
typedef kudamono tabemono;

clang code:

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的底层类型被记录为TypedefType中的"kudamono",而不是struct _poire中的"explatedtype"。

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的elaboration type。

所以clang中的规范类型是不与任何语法糖或修饰符或类型定义(如BuiltinType或RecordType)相关联的类型类。其他类型类(如ParentType、TypedefType或elaboration type)用于跟踪用户类型以进行诊断(错误消息…)。

看来你提出了一个有趣的观点。我已经弄明白了一些事情,但由于我现在无法测试我的直觉,所以我不能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;
}

解析typepedef时,得到的结果如下:

-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转储,它可以非常方便地理解你的代码将如何被解析:

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

现在,根据我的理解,我将VarDeclTypedefDecl进行比较:

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

这个TypedefDecl被命名为kudamono,并且具有类型struct _poire,这是从类型struct _poire 派生的类型

所以,奇怪的部分在这里。struct _poire被认为是来自struct _poire的类型定义。

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

typedef int numbers;

这一次,AST-dump产生:

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

我可以看到一个肮脏的方法来知道你的类型是否规范(不得到假阳性或假阴性):

检查QualType和标准的QualType是否相同

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

进行比较

那么,总结一下:

  • 你对规范类型的理解很好。
  • Clang似乎有一些手工类型的麻烦,但它应该是好的从通常的类型(如typedef int int32_t) Typedef。
  • 当您想知道一个类型是否规范时,您可以比较类型的名称和规范类型的名称,但这是相当肮脏的。对于通常的类型,isCanonical()工作得很好。