[cfe-dev] AST-dump

Manuel Klimek klimek at google.com
Mon Jun 10 04:38:20 PDT 2013


On Mon, Jun 10, 2013 at 12:11 PM, Pedro Delgado Perez
<pedro.delgado at uca.es>wrote:

>  Why do you care whether the default constructor is trivial? Wouldn't you
> also want to delete trivial constructors here?
>
> What doesn't match here is hasMethod(constructorDecl(isDefinition())).
> hasMethod will *not* loop over all declarations, but just the ones made in
> the recordDecl.
>
>
> To your specific problem (and tying into my above question): why not just
> constructorDecl(parameterCountIs(0), unless(isImplicit())
>
>
> Well, my purpose is to delete it so that the compiler provides one. It is
> pointless to delete it if the compiler is going to provide the same
> constructor again. There is no change, but if there isn't another option...
>
I don't think it's pointless to delete code that's unnecessary :)

> Maybe, I can look for the matcher you suggest
> "constructorDecl(parameterCountIs(0), unless(isImplicit())" and then only
> go on with the process determining if the constructor matched is a
> definition and it is not trivial as I was trying to do inside the matcher.
> Is that ok?
>
Well, you first have to get to the actual definition. Since it's not in the
class, you could take the declaration you found and look for redeclarations
that are definitions - one could build a matcher for that that would work
like hasRedeclaration(...).

Cheers,
/Manuel


> Thanks,
>
> Pedro.
>
>
>
>
> *El dia 10 jun 2013 11:49, Manuel Klimek <klimek at google.com> escribió:*
>
> On Mon, Jun 10, 2013 at 10:13 AM, Pedro Delgado Perez <
> pedro.delgado at uca.es> wrote:
>
>> Hi,
>>
>> Well, I'm going to rewind and try to give as much information of the
>> problem as possible to clarify it to everyone.
>>
>> My intention is the next: I want to retrieve the default constructor of a
>> class (not trivial if possible) and then to delete it so that the compiler
>> provides one. For this purpose, I need to verify that the class that default
>>
> Why do you care whether the default constructor is trivial? Wouldn't you
> also want to delete trivial constructors here?
>
>> constructor belongs to, doesn't have any other constructors (with at
>> least another constructor, the compiler doesn't provide the default
>> constructor).
>>
>> So, I created the next matcher:
>>
>> DeclarationMatcher DefaultConstructorMatcher =
>>  recordDecl(
>>            unless(hasMethod(constructorDecl(
>>                 allOf(hasAnyParameter(anything()),
>> unless(isImplicit()))))),
>>            hasMethod(constructorDecl(isDefinition(), parameterCountIs(0),
>>                  anyOf(hasAnyConstructorInitializer(isWritten()),
>> has(compoundStmt(has(stmt())))
>>
> What doesn't match here is hasMethod(constructorDecl(isDefinition())).
> hasMethod will *not* loop over all declarations, but just the ones made in
> the recordDecl.
>
> To your specific problem (and tying into my above question): why not just
> constructorDecl(parameterCountIs(0), unless(isImplicit()))?
>
>
>> )).bind("default_constructor"))
>>   ).bind("class_default_constructor");
>>
>> The first part helps me to discard classes with a constructor different
>> from the default constructor and the second part gives me the default
>> constructor I'm looking for.
>>
>> (Note: I put "unless(isImplicit())" to avoid other implicit constructors
>> provides by the compiler)
>>
>> Then, I can do:
>>
>>  if
>> (Result.Nodes.getNodeAs<clang::CXXRecordDecl>("class_default_constructor"))
>>          const CXXConstructorDecl *FS =
>> Result.Nodes.getNodeAs<clang::CXXConstructorDecl>("default_constructor");
>>
>> The problem now is:
>>
>> - Case 1:
>>
>> class E{
>>     public:
>>         E(){int a = 3;};
>>         int e;
>> };
>>
>>
>> Constructor E() is retrieved.
>>
>> - Case 2:
>> class E{
>>     public:
>>         E();
>>         int e;
>> };
>>
>>
>> E::E(){
>>    int a = 3;
>> }
>>
>> Constructor E() is not retrieved. I think the problem is that there are
>> two CXXConstructors in the AST, I suppose one for the declaration and the
>> other for the definition:
>>
>> <CXXConstructor ptr="0xc7de070" name="E" prototype="true">
>>    <FunctionProtoType ptr="0xc7de040" canonical="0xc7de040">
>>     <BuiltinType ptr="0xc7ddc30" canonical="0xc7ddc30"/>
>>     <parameters/>
>>    </FunctionProtoType>
>>   </CXXConstructor>
>>
>> ....
>>
>> <CXXConstructor used="1" ptr="0xc7de270" name="E" previous="0xc7de070"
>> prototype="true">
>>   <FunctionProtoType ptr="0xc7de040" canonical="0xc7de040">
>>    <BuiltinType ptr="0xc7ddc30" canonical="0xc7ddc30"/>
>>    <parameters/>
>>   </FunctionProtoType>
>>   <Stmt>
>> CompoundStmt 0xc7de378 <./ABC.h:8:7, line:10:1>
>> `-DeclStmt 0xc7de368 <line:9:2, col:11>
>>   `-VarDecl 0xc7de320 <col:2, col:10> a 'int'
>>     `-IntegerLiteral 0xc7de350 <col:10> 'int' 3
>>
>>   </Stmt>
>>  </CXXConstructor>
>>
>> With all this information everyone could test that this is true. Now,
>> responding your message:
>>
>> > *Did you mean "clang::Redeclarable< decl_type >" class?*
>> *
>> *
>> Yes.*
>> *
>>
>> I've been looking for a solution with this, but I definitively have no
>> idea what can I do with it.
>>
>> > *I think your suggestion might be useful to me, so that the second
>> declaration is not taken into account*
>> *
>> *
>> Yes, that is the idea.*
>> *
>>
>> Yes, but I need this only for the first part of the matcher, not for the
>> second part as I need to determine whether the constructor is trivial or
>> not.
>>
>> > *the matcher you are suggesting is previous to this or is included in
>> the same matcher I'm trying to build?*
>> *
>> *
>>
>> I don't understand what you mean.
>>
>> What I was asking was whether I needed to change my matcher
>> "DefaultConstructorMatcher" to do what you proposed or I had to create a
>> new one to act before my matcher.
>>
>> Thanks for your concern,
>>
>> Pedro.
>>
>>
>> *El dia 10 jun 2013 00:50, Gábor Kozár <kozargabor at gmail.com> escribió:*
>>
>> Hi,
>> I reread your previous e-mail, and I do not know why your matcher is not
>> working as intended in the example - I cannot find any problems with it.
>> Did you try filtering out the methods that have been declared before, to
>> see whether the E(); line or the E::E() line causes the matcher to fail?
>> > *Did you mean "clang::Redeclarable< decl_type >" class?*
>> *
>> *
>> Yes.*
>> *
>> > *I think your suggestion might be useful to me, so that the second
>> declaration is not taken into account*
>> *
>> *
>> Yes, that is the idea.*
>> *
>> > *but I can't still understand why the matcher is doing that if the
>> second declaration doesn't fit that matcher's conditions.*
>> *
>> *
>> Me neither, it appears that we're missing something.*
>> *
>> > *the matcher you are suggesting is previous to this or is included in
>> the same matcher I'm trying to build?*
>> *
>> *
>> I don't understand what you mean.*
>> *
>> Gabor
>>
>>
>> 2013/5/31 Pedro Delgado Perez <pedro.delgado at uca.es>
>>
>>> Did you mean "clang::Redeclarable< decl_type >" class? I think your
>>> suggestion might be useful to me, so that the second declaration is not
>>> taken into account,  but I can't still understand why the matcher is doing
>>> that if the second declaration doesn't fit that matcher's conditions.
>>>
>>> I will look into this, but the matcher you are suggesting is previous to
>>> this or is included in the same matcher I'm trying to build?
>>>
>>> Thanks,
>>>
>>> Pedro.
>>> *El dia 30 may 2013 21:36, Gábor Kozár <kozargabor at gmail.com> escribió:*
>>>
>>> Well, try filtering out declarations that are not first declarations -
>>> it looks to me that would solve your issue.
>>> I think you'll need to create a new matcher for this. In fact, this
>>> might be useful to implement generally and contribute to Clang. I believe
>>> there is a base class for redeclarable AST nodes, but can't remember the
>>> exact name - you should use that for your matcher.
>>>
>>>
>>> 2013/5/30 Pedro Delgado Perez <pedro.delgado at uca.es>
>>>
>>>> Hi,
>>>>
>>>> Default, copy, and move constructors are provided implicitly (under
>>>> various conditions - obviously if you have members that aren't default,
>>>> copy, or move constructible, you might not/cannot get all of those)
>>>>
>>>> Ok, but this keeps giving me trouble. I've used the isImplicit()
>>>> matcher to avoid those implicit constructors, but it isn't working how I
>>>> need yet.
>>>>
>>>> recordDecl(
>>>>     unless(hasMethod(constructorDecl(
>>>>                 allOf(hasAnyParameter(anything()), unless(isImplicit()))
>>>>
>>>> I know I shouldn't use the -ast-dump-xml option, but look at this. If I
>>>> have a class like this:
>>>>
>>>> class E{
>>>>     public:
>>>>         E(){int a = 3;};
>>>>         int e;
>>>> };
>>>>
>>>> This is the dump of the constructor:
>>>>
>>>> <CXXConstructor used="1" ptr="0xd7d8070" name="E" prototype="true">
>>>>    <FunctionProtoType ptr="0xd7d8040" canonical="0xd7d8040">
>>>>     <BuiltinType ptr="0xd7d7c30" canonical="0xd7d7c30"/>
>>>>     <parameters/>
>>>>    </FunctionProtoType>
>>>>    <Stmt>
>>>> CompoundStmt 0xd7d81a8 <./ABC.h:4:6, col:17>
>>>> `-DeclStmt 0xd7d8198 <col:7, col:16>
>>>>   `-VarDecl 0xd7d8150 <col:7, col:15> a 'int'
>>>>     `-IntegerLiteral 0xd7d8180 <col:15> 'int' 3
>>>>
>>>>    </Stmt>
>>>>   </CXXConstructor>
>>>>
>>>> And this case is working fine. But when the class is this other way:
>>>>
>>>> class E{
>>>>     public:
>>>>         E();
>>>>         int e;
>>>> };
>>>>
>>>> E::E(){
>>>>    int a = 3;
>>>> }
>>>>
>>>> The dump creates two CXXConstructors, I suppose one for the declaration
>>>> and the other for the definition:
>>>>
>>>> <CXXConstructor ptr="0xc7de070" name="E" prototype="true">
>>>>    <FunctionProtoType ptr="0xc7de040" canonical="0xc7de040">
>>>>     <BuiltinType ptr="0xc7ddc30" canonical="0xc7ddc30"/>
>>>>     <parameters/>
>>>>    </FunctionProtoType>
>>>>   </CXXConstructor>
>>>>
>>>> ....
>>>>
>>>> <CXXConstructor used="1" ptr="0xc7de270" name="E" previous="0xc7de070"
>>>> prototype="true">
>>>>   <FunctionProtoType ptr="0xc7de040" canonical="0xc7de040">
>>>>    <BuiltinType ptr="0xc7ddc30" canonical="0xc7ddc30"/>
>>>>    <parameters/>
>>>>   </FunctionProtoType>
>>>>   <Stmt>
>>>> CompoundStmt 0xc7de378 <./ABC.h:8:7, line:10:1>
>>>> `-DeclStmt 0xc7de368 <line:9:2, col:11>
>>>>   `-VarDecl 0xc7de320 <col:2, col:10> a 'int'
>>>>     `-IntegerLiteral 0xc7de350 <col:10> 'int' 3
>>>>
>>>>   </Stmt>
>>>>  </CXXConstructor>
>>>>
>>>> And this is the case my matcher is not retrieving the class E. I don't
>>>> know if clang it's considering that first  CxxConstructor as implicit...
>>>> The only difference I can see is the "used" attribute. I've tried creating
>>>> a simple matcher to use the isUsed() method of Decl class:
>>>>
>>>> namespace clang{
>>>>     namespace ast_matchers{
>>>>         AST_MATCHER(Decl, isUsed)
>>>>         {
>>>>             return Node.isUsed();
>>>>         }
>>>>     }
>>>> }
>>>>
>>>> but, this is having no influence.
>>>>
>>>> Maybe, I'm ignoring something.
>>>>
>>>> Thanks,
>>>>
>>>> Pedro.
>>>>
>>>>
>>>>
>>>> *El dia 28 may 2013 18:18, David Blaikie <dblaikie at gmail.com> escribió:
>>>> *
>>>>
>>>>
>>>>
>>>>
>>>> On Tue, May 28, 2013 at 2:07 AM, Pedro Delgado Perez <
>>>> pedro.delgado at uca.es> wrote:
>>>>
>>>> That seems like an approach that works. I don't know that there's a
>>>> different common property. Why's the default constructor different from the
>>>> copy constructor here?
>>>>
>>>> First of all, sorry but I made a mistake in the example:
>>>>
>>>>
>>>> class A{
>>>> 1.    A(){...}
>>>> 2.    A(int a){...}
>>>>
>>>> 3.    *A(const A& a){... ...}*
>>>> };
>>>>
>>>> What I mean is that I need to find if there is at least one constructor
>>>> that explicitly overloads the default constructor so that if I delete the
>>>> default constructor the compiler won't provide the default constructor. So,
>>>> my question was totally erroneous as the copy constructor does overload the
>>>> default constructor if provided, but I don't want to take it into account
>>>> if it wasn't explicitly provided.
>>>>
>>>> A better question is: which are the kind of constructors that the
>>>> compiler provides if no constructors are explicitly supplied? Only the
>>>> default and the copy constructor (in some situations)?
>>>> Default, copy, and move constructors are provided implicitly (under
>>>> various conditions - obviously if you have members that aren't default,
>>>> copy, or move constructible, you might not/cannot get all of those)
>>>>
>>>> If "unless(allOf(... ...))" is the best solution, could someone
>>>> enumerate the kind of constructors I must to indicate in that matcher?
>>>>
>>>> I'd suggest to not use ast-dump-xml any more. It's basically
>>>> deprecated, and hopefully it'll be removed soon. -ast-dump gives you all
>>>> the information (and more).
>>>>
>>>> Ok, I didn't know it.
>>>>
>>>> ... you can see that one is the default constructor and the other one
>>>> is the copy constructor. If you just put "G g;" into the code instead of
>>>> the second class, you'll also see that a simple use of G already triggers
>>>> the copy constructor to appear. Others are probably better able to explain
>>>> exactly when a copy constructor is created.
>>>>
>>>> Further information will be well received.
>>>>
>>>> Regards,
>>>>
>>>> Pedro.
>>>> *El dia 27 may 2013 12:24, Manuel Klimek <klimek at google.com> escribió:*
>>>> Hi Pedro,
>>>> first, please always send those mails also to cfe-dev. There are people
>>>> who are much more knowledgable about the AST on that list, and you'll often
>>>> get better answers faster that way :)
>>>> On Mon, May 27, 2013 at 10:00 AM, Pedro Delgado Perez <
>>>> pedro.delgado at uca.es> wrote:
>>>>
>>>> Sorry Manuel, but I prefer to ask you all the things I don't know
>>>> before you reply me:
>>>>
>>>> How do I know that a CXXConstructorDecl is a "simple" constructor of a
>>>> class. I mean, I want to find all the constructors in a class, but not the
>>>> copy, the move or things like this constructors. I'm not able to find this
>>>> in the documentation. To clarify this, I'm going to put an example:
>>>>
>>>> class A{
>>>> 1.    A(){...}
>>>> 2.    A(int a){...}
>>>> 3.    A(const &a){... ...}
>>>> };
>>>>
>>>> I want to look only for 1 and 2 and not for 3 when I ask:
>>>> recordDecl(hasMethod(constructDecl(...)));
>>>>
>>>> What can I do? Do I have to write "unless(allOf(isCopyConstructor(),
>>>> isMoveConstructor()...))" for each type of existing constructors?
>>>> That seems like an approach that works. I don't know that there's a
>>>> different common property. Why's the default constructor different from the
>>>> copy constructor here?
>>>>
>>>>
>>>> Thanks,
>>>>
>>>> Pedro.
>>>>
>>>>
>>>>
>>>> Hi Manuel,
>>>>
>>>> I would like to ask you something about the AST built by Clang if you
>>>> don't mind.  I've just have a look at your video  of introduction to Clang
>>>> AST (By the way, nice tutorial!) and I think that you may have an answer
>>>> for my trouble.
>>>>
>>>> Look, I was trying to look for classes that had only the default
>>>> constructor through ASTMatchers. Well, I tested my matcher with the next
>>>> classes:
>>>>
>>>> class G{
>>>> public:
>>>>         G():a(1){}
>>>>         int a;
>>>>         virtual int ma(int arg);
>>>> };
>>>>
>>>> class L: *public G*{
>>>>         public:
>>>>                 L(){v = 1;}
>>>>                 int b;
>>>>                 int h;
>>>>                 virtual int ma(int arg);
>>>>         private:
>>>>                 int v;
>>>>                 int f();
>>>> };
>>>>
>>>> My matcher only retrieved the class 'L' and not the 'G'. I was
>>>> wondering what would be the problem when I had a look to the ast-dump-xml
>>>> option:
>>>> I'd suggest to not use ast-dump-xml any more. It's basically
>>>> deprecated, and hopefully it'll be removed soon. -ast-dump gives you all
>>>> the information (and more).
>>>>
>>>>  <CXXRecord ptr="0xd695f30" name="G" typeptr="0xd695f80">
>>>>   <CXXRecord ptr="0xd695fd0" name="G" typeptr="0xd695f80"/>
>>>>   <AccessSpec ptr="0xd696020" access="public"/>
>>>>   *<CXXConstructor* used="1" ptr="0xd696080" name="G" prototype="true">
>>>>    <FunctionProtoType ptr="0xd696050" canonical="0xd696050">
>>>>     <BuiltinType ptr="0xd695c40" canonical="0xd695c40"/>
>>>>     <parameters/>
>>>>    </FunctionProtoType>
>>>>    <Stmt>
>>>> CompoundStmt 0xd696450 <tst.cpp:7:10, col:11>
>>>>    </Stmt>
>>>>   </CXXConstructor>
>>>>
>>>> ....
>>>>
>>>> *<CXXConstructor* ptr="0xd6aefc0" name="G" prototype="true"
>>>> inline="true">
>>>>    <FunctionProtoType ptr="0xd6af050" canonical="0xd6af030"
>>>> exception_spec="unevaluated">
>>>>     <BuiltinType ptr="0xd695c40" canonical="0xd695c40"/>
>>>>     <parameters>
>>>>      <LValueReferenceType ptr="0xd696240" canonical="0xd696240">
>>>>       <QualType const="true">
>>>>        <RecordType ptr="0xd695f80" canonical="0xd695f80">
>>>>         <CXXRecord ref="0xd695f30"/>
>>>>        </RecordType>
>>>>       </QualType>
>>>>      </LValueReferenceType>
>>>>     </parameters>
>>>>    </FunctionProtoType>
>>>>    <ParmVar ptr="0xd6af070" name="" initstyle="c">
>>>>     <LValueReferenceType ptr="0xd696240" canonical="0xd696240">
>>>>      <QualType const="true">
>>>>       <RecordType ptr="0xd695f80" canonical="0xd695f80">
>>>>        <CXXRecord ref="0xd695f30"/>
>>>>       </RecordType>
>>>>      </QualType>
>>>>     </LValueReferenceType>
>>>>    </ParmVar>
>>>>   </CXXConstructor>
>>>>  </CXXRecord>
>>>>
>>>> Why class 'G' has two constructors? If I change the test program in
>>>> order that class 'L' doesn't inherits from class 'G', this doesn't happen
>>>> (class 'G' only has one constructor in the ast-dump-xml) Could you lend me
>>>> a hand?
>>>> If you look at -ast-dump:
>>>> $ clang -cc1 -ast-dump t4.cc
>>>> <snip>
>>>> |-CXXRecordDecl 0x37faf80 <t4.cc:1:1, line:6:1> class G
>>>> <snip>
>>>> | |-CXXConstructorDecl 0x37fb1c0 <line:3:3, col:15> G 'void (void)'
>>>> | | |-CXXCtorInitializer Field 0x37fb290 'a' 'int'
>>>> | | | |-IntegerLiteral 0x382d018 <col:11> 'int' 1
>>>> | | `-CompoundStmt 0x382d0a0 <col:14, col:15>
>>>> <snip>
>>>> | `-CXXConstructorDecl 0x382da70 <col:7> G 'void (const class G &)'
>>>> inline
>>>> |   `-ParmVarDecl 0x382f820 <col:7> 'const class G &'
>>>> <snip>
>>>> ... you can see that one is the default constructor and the other one
>>>> is the copy constructor. If you just put "G g;" into the code instead of
>>>> the second class, you'll also see that a simple use of G already triggers
>>>> the copy constructor to appear. Others are probably better able to explain
>>>> exactly when a copy constructor is created.
>>>> cheers,
>>>> /Manuel
>>>>
>>>> _______________________________________________
>>>> cfe-dev mailing list
>>>> cfe-dev at cs.uiuc.edu
>>>>
>>>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
>>>>
>>>>
>>>> _______________________________________________
>>>> cfe-dev mailing list
>>>> cfe-dev at cs.uiuc.edu
>>>>
>>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
>>>
>>>
>>
>> _______________________________________________
>> cfe-dev mailing list
>> cfe-dev at cs.uiuc.edu
>>
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20130610/86f7a0a4/attachment.html>


More information about the cfe-dev mailing list