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

John McCall rjmccall at apple.com
Fri Dec 14 14:46:45 PST 2012


On Dec 14, 2012, at 2:36 PM, Peeter Joot <peeter.joot at gmail.com> wrote:

> 
> > 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?

It's possible that we don't even bother setting this bit in sufficiently trivial cases.

I think the right approach is:
1.  Ignore default constructors that satisfy isTrivial().
2.  Check getDefinition().
2a.  If that doesn't return something, the constructor must be implemented elsewhere, which is a direct cause for a global constructor.
2b.  If it does return something, check whether that's isImplicit() || isDefaulted().  If not, that's a direct cause.
2c.  Otherwise, recurse over its initializers.

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


More information about the cfe-dev mailing list