<html>
  <head>
    <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    <div class="moz-cite-prefix">On 08/10/14 17:22, Reid Kleckner wrote:<br>
    </div>
    <blockquote
cite="mid:CACs=tyLKC9x10Eiw8Z-cSBYFyNFv4M+FLRtzA2GgCdbWGrKBBw@mail.gmail.com"
      type="cite">
      <div dir="ltr">
        <div class="gmail_extra">
          <div class="gmail_quote">On Wed, Oct 8, 2014 at 6:02 AM, Peter
            Stirling <span dir="ltr"><<a moz-do-not-send="true"
                href="mailto:peter@pjstirling.plus.com" target="_blank">peter@pjstirling.plus.com</a>></span>
            wrote:<br>
            <blockquote class="gmail_quote" style="margin:0 0 0
              .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi
              again,<br>
              <br>
              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:<br>
              <br>
              bool shouldBeTemplate(clang::DeclContext const* context) {<br>
                if(context->getDeclKind() == clang::Decl::CXXRecord)
              {<br>
                  auto record =
              llvm::cast<clang::CXXRecordDecl>(context);<br>
                  auto dname = record->getDeclName();<br>
                  // there will always be a parent<br>
                  auto cursor =
              context->getParent()->lookup(dname);<br>
                  for(auto named : cursor) {<br>
                    if(llvm::isa<clang::ClassTemplateDecl>(named))
              {<br>
                      return true;<br>
                    }<br>
                  }<br>
                }<br>
                return false;<br>
              }<br>
            </blockquote>
            <div><br>
            </div>
            <div>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.</div>
          </div>
        </div>
      </div>
    </blockquote>
    Yes, this works, thanks.<br>
    <blockquote
cite="mid:CACs=tyLKC9x10Eiw8Z-cSBYFyNFv4M+FLRtzA2GgCdbWGrKBBw@mail.gmail.com"
      type="cite">
      <div dir="ltr">
        <div class="gmail_extra">
          <div class="gmail_quote">
            <div> </div>
            <blockquote class="gmail_quote" style="margin:0 0 0
              .8ex;border-left:1px #ccc solid;padding-left:1ex"> 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:<br>
              <br>
              bool isIncompleteType(clang::QualType inType) {<br>
                if(inType->isRecordType()) {<br>
                  auto realType =
              inType->getAs<clang::RecordType>();`<br>
                  auto decl =
              realType->getDecl()->getCanonicalDecl();<br>
                  if(decl->getDefinition() ||<br>
              llvm::isa<clang::ClassTemplateSpecializationDecl>(decl))

              {<br>
                    return false;<br>
                  }<br>
                  else {<br>
                    return true;<br>
                  }<br>
                }<br>
                return false;<br>
              }<br>
            </blockquote>
            <div><br>
            </div>
            <div>I think you can compute this more directly with
              inType->isIncompleteType().</div>
          </div>
        </div>
      </div>
    </blockquote>
    <br>
    Thanks for the suggestion, I hadn't seen that either. Unfortunately
    it doesn't work, for the same cases as getDefinition(), these are
    (from my test data):<br>
    <br>
      std::fpos<__mbstate_t > <br>
      std::reverse_iterator<__gnu_cxx::__normal_iterator<char
    const * , std::basic_string<char , std::char_traits<char >
    , std::allocator<char > > > > <br>
      std::reverse_iterator<__gnu_cxx::__normal_iterator<char* ,
    std::basic_string<char , std::char_traits<char > ,
    std::allocator<char > > > > <br>
      std::reverse_iterator<__gnu_cxx::__normal_iterator<wchar_t
    const * , std::basic_string<wchar_t , std::char_traits<wchar_t
    > , std::allocator<wchar_t > > > > <br>
      std::reverse_iterator<__gnu_cxx::__normal_iterator<wchar_t*
    , std::basic_string<wchar_t , std::char_traits<wchar_t > ,
    std::allocator<wchar_t > > > > <br>
      __gnu_cxx::__normal_iterator<char16_t* ,
    std::basic_string<char16_t , std::char_traits<char16_t > ,
    std::allocator<char16_t > > > <br>
      __gnu_cxx::__normal_iterator<char16_t const * ,
    std::basic_string<char16_t , std::char_traits<char16_t > ,
    std::allocator<char16_t > > > <br>
      std::reverse_iterator<__gnu_cxx::__normal_iterator<char16_t
    const * , std::basic_string<char16_t ,
    std::char_traits<char16_t > , std::allocator<char16_t >
    > > > <br>
      std::reverse_iterator<__gnu_cxx::__normal_iterator<char16_t*
    , std::basic_string<char16_t , std::char_traits<char16_t >
    , std::allocator<char16_t > > > > <br>
      std::initializer_list<char16_t > <br>
      __gnu_cxx::__normal_iterator<char32_t* ,
    std::basic_string<char32_t , std::char_traits<char32_t > ,
    std::allocator<char32_t > > > <br>
      __gnu_cxx::__normal_iterator<char32_t const * ,
    std::basic_string<char32_t , std::char_traits<char32_t > ,
    std::allocator<char32_t > > > <br>
      std::reverse_iterator<__gnu_cxx::__normal_iterator<char32_t
    const * , std::basic_string<char32_t ,
    std::char_traits<char32_t > , std::allocator<char32_t >
    > > > <br>
      std::reverse_iterator<__gnu_cxx::__normal_iterator<char32_t*
    , std::basic_string<char32_t , std::char_traits<char32_t >
    , std::allocator<char32_t > > > > <br>
      std::initializer_list<char32_t > <br>
      std::istreambuf_iterator<char , std::char_traits<char >
    > <br>
      std::ostreambuf_iterator<char , std::char_traits<char >
    > <br>
      std::istreambuf_iterator<wchar_t , std::char_traits<wchar_t
    > > <br>
      std::ostreambuf_iterator<wchar_t , std::char_traits<wchar_t
    > > <br>
      __gnu_cxx::__normal_iterator<char* , std::vector<char ,
    std::allocator<char > > > <br>
      __gnu_cxx::__normal_iterator<char const * , std::vector<char
    , std::allocator<char > > > <br>
      std::reverse_iterator<__gnu_cxx::__normal_iterator<char
    const * , std::vector<char , std::allocator<char > >
    > > <br>
      std::reverse_iterator<__gnu_cxx::__normal_iterator<char* ,
    std::vector<char , std::allocator<char > > > > <br>
      __gnu_cxx::__normal_iterator<double const * ,
    std::vector<double , std::allocator<double > > > <br>
      std::reverse_iterator<__gnu_cxx::__normal_iterator<double
    const * , std::vector<double , std::allocator<double > >
    > > <br>
      std::reverse_iterator<__gnu_cxx::__normal_iterator<double* ,
    std::vector<double , std::allocator<double > > > >
    <br>
      __gnu_cxx::__normal_iterator<unsigned int* ,
    std::vector<unsigned int , std::allocator<unsigned int >
    > > <br>
      std::reverse_iterator<__gnu_cxx::__normal_iterator<unsigned
    int const * , std::vector<unsigned int ,
    std::allocator<unsigned int > > > > <br>
      std::reverse_iterator<__gnu_cxx::__normal_iterator<unsigned
    int* , std::vector<unsigned int , std::allocator<unsigned int
    > > > > <br>
      std::initializer_list<unsigned int > <br>
      std::_List_iterator<TagLib::ByteVector > <br>
      std::_List_const_iterator<TagLib::ByteVector > <br>
     
    std::reverse_iterator<std::_List_const_iterator<TagLib::ByteVector
    > > <br>
      std::reverse_iterator<std::_List_iterator<TagLib::ByteVector
    > > <br>
      std::initializer_list<TagLib::ByteVector > <br>
      std::_List_iterator<TagLib::String > <br>
      std::_List_const_iterator<TagLib::String > <br>
     
    std::reverse_iterator<std::_List_const_iterator<TagLib::String
    > > <br>
      std::reverse_iterator<std::_List_iterator<TagLib::String
    > > <br>
      std::initializer_list<TagLib::String > <br>
    <br>
    <blockquote
cite="mid:CACs=tyLKC9x10Eiw8Z-cSBYFyNFv4M+FLRtzA2GgCdbWGrKBBw@mail.gmail.com"
      type="cite">
      <div dir="ltr">
        <div class="gmail_extra">
          <div class="gmail_quote">
            <div><br>
            </div>
            <blockquote class="gmail_quote" style="margin:0 0 0
              .8ex;border-left:1px #ccc solid;padding-left:1ex"> 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.<br>
            </blockquote>
            <div><br>
            </div>
            <div>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.</div>
          </div>
        </div>
      </div>
    </blockquote>
    <br>
    The functions that I've hit in my test data are:<br>
      __atomic_fetch_add();<br>
      __builtin_isfinite();<br>
      __builtin_isinf();<br>
      __builtin_isnan();<br>
      __builtin_isnormal();<br>
      __builtin_isgreater();<br>
      __builtin_isgreaterequal();<br>
      __builtin_isless();<br>
      __builtin_islessequal();<br>
      __builtin_islessgreater(); <br>
    <br>
    For all of the above FunctionDecl::getBuiltinID() returns non-zero.<br>
    <br>
    <blockquote
cite="mid:CACs=tyLKC9x10Eiw8Z-cSBYFyNFv4M+FLRtzA2GgCdbWGrKBBw@mail.gmail.com"
      type="cite">
      <div dir="ltr">
        <div class="gmail_extra">
          <div class="gmail_quote">
            <blockquote class="gmail_quote" style="margin:0 0 0
              .8ex;border-left:1px #ccc solid;padding-left:1ex">
              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?</blockquote>
            <div><br>
            </div>
            <div>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:</div>
            <div>  // Result is the set BasesSeen.</div>
            <div>  void doit(BasesSeen, RD)</div>
            <div>    if (RD in BasesSeen)</div>
            <div>      return</div>
            <div>    BasesSeen.insert(RD)</div>
            <div>    for (Base in RD.bases())</div>
            <div>      doit(BasesSeen, Base)</div>
            <div><br>
            </div>
            <div>Hope that helps!</div>
          </div>
        </div>
      </div>
    </blockquote>
    <br>
    I'll give this a bash, though I'll need to keep track of virtual and
    normal parents separately. I was trying to imagine a bottom-up
    recursive algorithm, which wasn't working. Thanks for the
    suggestion!<br>
    <br>
  </body>
</html>