[cfe-dev] better way to test for explicit C++ constructor?

Peeter Joot peeter.joot at gmail.com
Fri Dec 14 14:36:50 PST 2012


> > How do I walk over the initializers in that constructor?  I'd tried:
>
[snip]

> 1.  Look at the constructor: getConstructor().
> 2.  Check whether it's a implicitly-defined default constructor:
> isDefaultConstructor(), isImplicitlyDefined().  If not, you've found your
> problem right there.
> 3.  Iterate over the initializers: init_begin(), init_end().
> 4.  I believe the expression for each initializer should always be a
> CXXConstructExpr.  Recurse.
>

With the tips supplied, I was able to cobble together the global detection
and the initializer iteration portions of above.  Each initializer turns
out to be a CXXCtorInitializer, but the CXXConstructExpr can be found from
that:

   void recurseOverConstructorDecls( CXXConstructorDecl * c, string
subobject )
   {
      for ( CXXConstructorDecl::init_iterator b = c->init_begin(), e =
c->init_end() ;
            b != e ; ++b )
      {
         CXXCtorInitializer *    i        = *b ;
         FieldDecl *             f        = i->getMember() ;
         Expr *                  Init     = i->getInit() ;
         string                  subfield = subMemberString( subobject,
f->getName().str() ) ;

         if ( const CXXConstructExpr * r = dyn_cast<CXXConstructExpr>( Init
) )
         {
            CXXConstructorDecl * cInner = r->getConstructor() ;

            if ( !cInner->isImplicitlyDefined() )
            {
               cout << "!implicit: " << subfield << endl ;
            }

            recurseOverConstructorDecls( cInner, subfield ) ;
         }
      }
   }

   bool VisitVarDecl( VarDecl * var )
   {
      // modified from Eli's email "Here's the code used to implement
-Wglobal-constructor:"
      Expr *         Init     = var->getInit() ;
      bool           IsGlobal = var->hasGlobalStorage() &&
!var->isStaticLocal() ;
      QualType       type     = var->getType();
      QualType       baseType = context.getBaseElementType( type ) ;

      if ( !var->getDeclContext()->isDependentContext() && Init &&
!Init->isValueDependent() )
      {
         if ( IsGlobal && !var->isConstexpr() &&
              !Init->isConstantInitializer( context,
baseType->isReferenceType() ) )
         {
            if ( const CXXConstructExpr * r = dyn_cast<CXXConstructExpr>(
Init ) )
            {
               CXXConstructorDecl * c = r->getConstructor() ;

               recurseOverConstructorDecls( c, var->getName().str() ) ;
            }
         }
      }

      return true ;
   }

However, on the following sample:

    struct withConstructor
    {
       int x ;

       withConstructor() : x(3) {}
    } ;

    struct noConstructor
    {
       int x ;
    } ;

    struct krcb
    {
       noConstructor     noCons ;
       withConstructor   withCons;
    } ;

    krcb k ;

I get:

    !implicit: k.noCons
    !implicit: k.withCons

despite the fact that the type noConstructor is POD.  It appears that
checking for the non trivial constructor isn't really what the
isImplicitlyDefined() function does. Calling isDefaultConstructor() doesn't
help since my explicit constructor is also a default constructor, but is
also non-trivial.  How can I additionally narrow this down?

Alternately, if there was a way to lookup the CXXRecordDecl that's
associated with the FieldDecl, then the functions
like hasUserDeclaredConstructor() could be called.  However, I'm not sure
how to find this RecordDecl from any of the types available from the init
expression.

-- 
Peeter
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20121214/f44b9eda/attachment.html>


More information about the cfe-dev mailing list