Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/FixInit.cc

    r03b812d2 r79970ed  
    3333#include "GenPoly/PolyMutator.h"
    3434#include "SynTree/AddStmtVisitor.h"
     35#include "CodeGen/GenType.h"  // for warnings
    3536
    3637bool ctordtorp = false;
     
    174175                        virtual Expression * mutate( ImplicitCopyCtorExpr * impCpCtorExpr );
    175176                };
     177
     178                class WarnStructMembers : public Visitor {
     179                  public:
     180                        typedef Visitor Parent;
     181                        /// warn if a user-defined constructor or destructor is missing calls for
     182                        /// a struct member or if a member is used before constructed
     183                        static void warnings( std::list< Declaration * > & translationUnit );
     184
     185                        virtual void visit( FunctionDecl * funcDecl );
     186
     187                        virtual void visit( MemberExpr * memberExpr );
     188                        virtual void visit( ApplicationExpr * appExpr );
     189
     190                  private:
     191                        void handleFirstParam( Expression * firstParam );
     192
     193                        FunctionDecl * function = 0;
     194                        std::set< DeclarationWithType * > unhandled;
     195                        ObjectDecl * thisParam = 0;
     196                };
    176197        } // namespace
    177198
     
    187208                // FixCopyCtors must happen after FixInit, so that destructors are placed correctly
    188209                FixCopyCtors::fixCopyCtors( translationUnit );
     210
     211                WarnStructMembers::warnings( translationUnit );
    189212        }
    190213
     
    231254                }
    232255
     256                void WarnStructMembers::warnings( std::list< Declaration * > & translationUnit ) {
     257                        if ( true ) { // fix this condition to skip this pass if warnings aren't enabled
     258                                WarnStructMembers warner;
     259                                acceptAll( translationUnit, warner );
     260                        }
     261                }
     262
    233263                Expression * InsertImplicitCalls::mutate( ApplicationExpr * appExpr ) {
    234264                        appExpr = dynamic_cast< ApplicationExpr * >( Mutator::mutate( appExpr ) );
     
    242272                                        FunctionType * ftype = dynamic_cast< FunctionType * >( GenPoly::getFunctionType( funcDecl->get_type() ) );
    243273                                        assert( ftype );
    244                                         if ( (funcDecl->get_name() == "?{}" || funcDecl->get_name() == "?=?") && ftype->get_parameters().size() == 2 ) {
     274                                        if ( (isConstructor( funcDecl->get_name() ) || funcDecl->get_name() == "?=?") && ftype->get_parameters().size() == 2 ) {
    245275                                                Type * t1 = ftype->get_parameters().front()->get_type();
    246276                                                Type * t2 = ftype->get_parameters().back()->get_type();
     
    253283                                                        return appExpr;
    254284                                                } // if
    255                                         } else if ( funcDecl->get_name() == "^?{}" ) {
     285                                        } else if ( isDestructor( funcDecl->get_name() ) ) {
    256286                                                // correctness: never copy construct arguments to a destructor
    257287                                                return appExpr;
     
    670700                        } // switch
    671701                }
     702
     703                bool checkWarnings( FunctionDecl * funcDecl ) {
     704                        // only check for warnings if the current function is a user-defined
     705                        // constructor or destructor
     706                        if ( ! funcDecl ) return false;
     707                        if ( ! funcDecl->get_statements() ) return false;
     708                        return isCtorDtor( funcDecl->get_name() ) && ! LinkageSpec::isOverridable( funcDecl->get_linkage() );
     709                }
     710
     711                void WarnStructMembers::visit( FunctionDecl * funcDecl ) {
     712                        WarnStructMembers old = *this;
     713                        *this = WarnStructMembers();
     714
     715                        function = funcDecl;
     716                        if ( checkWarnings( funcDecl ) ) {
     717                                FunctionType * type = funcDecl->get_functionType();
     718                                assert( ! type->get_parameters().empty() );
     719                                thisParam = safe_dynamic_cast< ObjectDecl * >( type->get_parameters().front() );
     720                                PointerType * ptrType = safe_dynamic_cast< PointerType * > ( thisParam->get_type() );
     721                                StructInstType * structType = dynamic_cast< StructInstType * >( ptrType->get_base() );
     722                                if ( structType ) {
     723                                        StructDecl * structDecl = structType->get_baseStruct();
     724                                        for ( Declaration * member : structDecl->get_members() ) {
     725                                                if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( member ) ) {
     726                                                        // record all of the struct type's members that need to be constructed or
     727                                                        // destructed by the end of the function
     728                                                        unhandled.insert( field );
     729                                                }
     730                                        }
     731                                }
     732                        }
     733                        Parent::visit( funcDecl );
     734
     735                        for ( DeclarationWithType * member : unhandled ) {
     736                                // emit a warning for each unhandled member
     737                                warn( "in ", CodeGen::genType( function->get_functionType(), function->get_name() ), ", member ", member->get_name(), " may not have been ", isConstructor( funcDecl->get_name() ) ? "constructed" : "destructed" );
     738                        }
     739
     740                        *this = old;
     741                }
     742
     743                void WarnStructMembers::visit( ApplicationExpr * appExpr ) {
     744                        if ( ! checkWarnings( function ) ) return;
     745
     746                        std::string fname = getFunctionName( appExpr );
     747                        if ( fname == function->get_name() ) {
     748                                // call to same kind of function
     749                                Expression * firstParam = appExpr->get_args().front();
     750
     751                                if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( firstParam ) ) {
     752                                        // if calling another constructor on thisParam, assume that function handles
     753                                        // all members - if it doesn't a warning will appear in that function.
     754                                        if ( varExpr->get_var() == thisParam ) {
     755                                                unhandled.clear();
     756                                        }
     757                                } else {
     758                                        // if first parameter is a member expression then
     759                                        // remove the member from unhandled set.
     760                                        handleFirstParam( firstParam );
     761                                }
     762                        } else if ( fname == "?=?" && isIntrinsicCallExpr( appExpr ) ) {
     763                                // forgive use of intrinsic assignment to construct, since instrinsic constructors
     764                                // codegen as assignment anyway.
     765                                assert( appExpr->get_args().size() == 2 );
     766                                handleFirstParam( appExpr->get_args().front() );
     767                        }
     768
     769                        Parent::visit( appExpr );
     770                }
     771
     772                void WarnStructMembers::handleFirstParam( Expression * firstParam ) {
     773                        using namespace std;
     774                        if ( AddressExpr * addrExpr = dynamic_cast< AddressExpr * >( firstParam ) ) {
     775                                if ( MemberExpr * memberExpr = dynamic_cast< MemberExpr * >( addrExpr->get_arg() ) ) {
     776                                        if ( ApplicationExpr * deref = dynamic_cast< ApplicationExpr * >( memberExpr->get_aggregate() ) ) {
     777                                                if ( getFunctionName( deref ) == "*?" && deref->get_args().size() == 1 ) {
     778                                                        if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( deref->get_args().front() ) ) {
     779                                                                if ( varExpr->get_var() == thisParam ) {
     780                                                                        unhandled.erase( memberExpr->get_member() );
     781                                                                }
     782                                                        }
     783                                                }
     784                                        }
     785                                }
     786                        }
     787                }
     788
     789                void WarnStructMembers::visit( MemberExpr * memberExpr ) {
     790                        if ( ! checkWarnings( function ) ) return;
     791                        if ( ! isConstructor( function->get_name() ) );
     792
     793                        if ( ApplicationExpr * deref = dynamic_cast< ApplicationExpr * >( memberExpr->get_aggregate() ) ) {
     794                                if ( getFunctionName( deref ) == "*?" && deref->get_args().size() == 1 ) {
     795                                        if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( deref->get_args().front() ) ) {
     796                                                if ( varExpr->get_var() == thisParam ) {
     797                                                        if ( unhandled.count( memberExpr->get_member() ) ) {
     798                                                                // emit a warning because a member was used before it was constructed
     799                                                                warn( "in ", CodeGen::genType( function->get_functionType(), function->get_name() ), ", member ", memberExpr->get_member()->get_name(), " used before being constructed" );
     800                                                        }
     801                                                }
     802                                        }
     803                                }
     804                        }
     805                        Parent::visit( memberExpr );
     806                }
    672807        } // namespace
    673808} // namespace InitTweak
Note: See TracChangeset for help on using the changeset viewer.