Search code examples
c++cclangllvmclang++

What are canonical types in Clang?


I have a simple header parser based on clang and I get the typedefs from some source.

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

After parsing this I have a clang::TypedefDecl then I get the clang::QualType of the typedef with clang::TypedefDecl::getUnderlyingType()

With the QualType if I use the getAsString method I can find the "struct _poire" std::string. All this is Ok.

The problem is if I try to see if this type is a canonical type, with QualType::isCanonical(), it returns false.

So I try to get the canonical type with QualType::getCanonicalType().getAsString() and it returns the same string "struct _poire".

according to the clang reference on type http://clang.llvm.org/docs/InternalsManual.html#canonical-types , I thought that the isCanonical() should return true when no typedef is involved.

So what are really canonical type?


Solution

  • After further investigations and a question in the clang mailing list, I think I have figured out what is a canonical type.

    Firstly it 's important to not focus on the QualType in order to understand Canonical Type. Look this (code /pseudocode):

    source file :

    typedef struct _poire kudamono; 
    

    clang code :

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

    c and t are not the same QualType even if they have the same string representation. QualType are used to associate qualifiers ("const", "volatile"...) with a clang type. There are a lot of Clang Types classes because clang needs to keep tracks of the user-specified types for diagnostics.( http://clang.llvm.org/docs/InternalsManual.html#the-type-class-and-its-subclasses and http://clang.llvm.org/doxygen/classclang_1_1Type.html )

    The clang types used depends heavily on the syntaxic sugars or modifiers associated with the C/C++ types in the source file.

    In the exemple above, the QualType t is associated with an ElaboratedType. This type allows to keep track of the type name as written in the source code. But the canonical QualType is associated with a RecordType.

    Another example: source file:

    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
    

    Here we can see that the underlying type of the typedef is recorded as "kudamono" a TypedefType and not "struct _poire" an ElaboratedType.

    The canonical type for the TypedefType "kudamono" is a RecordType "struct _poire".

    Another examples that I have had from the clang mailing-list ( http://article.gmane.org/gmane.comp.compilers.clang.devel/38371/match=canonical+type ):

    Consider:

    int (x);
    

    The type of x is not a BuiltinType; it's a ParenType whose canonical type is a BuiltinType. And given

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

    the type of x will probably be represented as an ElaboratedType whose canonical type is a RecordType.

    So the canonical Type in clang are classes of types that are not associated with any syntaxic sugars or modifiers or typedef (like BuiltinType or RecordType). Other classes of types (like ParentType, TypedefType or ElaboratedType) are used to keep tracks of the user type for diagnostics (error message ...).