[cfe-dev] Further AST spelunking

Reid Kleckner rnk at google.com
Wed Oct 8 09:22:46 PDT 2014


On Wed, Oct 8, 2014 at 6:02 AM, Peter Stirling <peter at pjstirling.plus.com>
wrote:

> Hi again,
>
> I'm still plodding away at my SWIG alternative. As I said in my previous
> email, typedefs that are declared within templates but which do not depend
> on any of the template arguments are held in the AST as children of a
> CXXRecordDecl ignorant of the fact that it should be a template and what
> its arguments should be. This is a problem for me because it means that I
> can't print a properly scoped name to identify the type for c++ code. I
> have managed to work around this by adding a check for whether a typedef is
> a child of a CXXRecordDecl but should really be a child of a template. The
> code I'm using appears to work, but I'd like to double-check that it is
> appropriate:
>
> bool shouldBeTemplate(clang::DeclContext const* context) {
>   if(context->getDeclKind() == clang::Decl::CXXRecord) {
>     auto record = llvm::cast<clang::CXXRecordDecl>(context);
>     auto dname = record->getDeclName();
>     // there will always be a parent
>     auto cursor = context->getParent()->lookup(dname);
>     for(auto named : cursor) {
>       if(llvm::isa<clang::ClassTemplateDecl>(named)) {
>         return true;
>       }
>     }
>   }
>   return false;
> }
>

I think what you are trying to compute is equivalent to
context->isDependentContext(), which returns true if this context is nested
inside any template, class or function.


> Another issue is that, while it is safe to handle values that are pointers
> to incomplete structure types, it is illegal to call a function that takes
> an argument value or returns a result value that is an incomplete type. My
> first attempt was to check for RecordTypes and call
> CXXRecordDecl::getDefinition(), but for some (but confusingly to me, not
> all) template types getDefinition() returns NULL even though the type isn't
> incomplete, is this expected? The code that I'm using is below, I also
> wonder whether getCanonicalDecl() is overkill here:
>
> bool isIncompleteType(clang::QualType inType) {
>   if(inType->isRecordType()) {
>     auto realType = inType->getAs<clang::RecordType>();`
>     auto decl = realType->getDecl()->getCanonicalDecl();
>     if(decl->getDefinition() ||
> llvm::isa<clang::ClassTemplateSpecializationDecl>(decl)) {
>       return false;
>     }
>     else {
>       return true;
>     }
>   }
>   return false;
> }
>

I think you can compute this more directly with inType->isIncompleteType().

I've also discovered that parsing code that calls a builtin function causes
> a no-argument, returns-int declaration to be inserted. It's been a while,
> but as I remember, in C this kind of declaration actually means that the
> function takes an unspecified number of arguments, but each one passed
> should be promoted to the size of an int (did they update this since
> pointers became much larger than ints?). In C++ it means something rather
> different. It seems a bit odd to me that builtin functions don't have the
> correct declaration inserted, since the compiler must have them on hand
> somewhere.
>

Yes, in C, this is a no-prototype, implicit int return function. I'm not
sure what kind of builtin function you're referring to. If the name starts
with __builtin_, then the compiler knows the prototype. If it's a libc
function like "fprintf()", then you will probably get a warning and the
implicit declaration you describe. In C++, you shouldn't get these implicit
declarations, it's just an error.


> Finally, I need to generate the list of base classes that a derived class
> can be implicitly converted to. I have an intuitive understanding of when
> it should work, but when I try to think of an algorithm to sort out
> arbitrarily-evil trees combining virtual and normal inheritance I go a bit
> cross-eyed. Can anyone point me at something that will help me figure this
> out?


The inheritance hierarchy is always a directed acyclic graph, so you can
walk it recursively as long as you remember what you've already seen. If
you have a class with multiple base subobjects of the same type and you
don't care about which one an implicit conversion would pick, then you can
do depth-first search and throw everything into a set:
  // Result is the set BasesSeen.
  void doit(BasesSeen, RD)
    if (RD in BasesSeen)
      return
    BasesSeen.insert(RD)
    for (Base in RD.bases())
      doit(BasesSeen, Base)

Hope that helps!
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20141008/501174ca/attachment.html>


More information about the cfe-dev mailing list