Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Virtual/ExpandCasts.cc

    rc6b4432 rbccd70a  
    2424#include "AST/Expr.hpp"
    2525#include "AST/Pass.hpp"
     26#include "Common/PassVisitor.h"    // for PassVisitor
    2627#include "Common/ScopedMap.h"      // for ScopedMap
    2728#include "Common/SemanticError.h"  // for SemanticError
    2829#include "SymTab/Mangler.h"        // for mangleType
     30#include "SynTree/Declaration.h"   // for ObjectDecl, StructDecl, FunctionDecl
     31#include "SynTree/Expression.h"    // for VirtualCastExpr, CastExpr, Address...
     32#include "SynTree/Mutator.h"       // for mutateAll
     33#include "SynTree/Type.h"          // for Type, PointerType, StructInstType
     34#include "SynTree/Visitor.h"       // for acceptAll
    2935
    3036namespace Virtual {
     
    3743}
    3844
     45bool is_type_id_object( const ObjectDecl * objectDecl ) {
     46        const std::string & objectName = objectDecl->name;
     47        return is_prefix( "__cfatid_", objectName );
     48}
     49
    3950bool is_type_id_object( const ast::ObjectDecl * decl ) {
    4051        return is_prefix( "__cfatid_", decl->name );
     
    4455
    4556        /// Maps virtual table types the instance for that type.
     57        class VirtualTableMap final {
     58                ScopedMap<std::string, ObjectDecl *> vtable_instances;
     59        public:
     60                void enterScope() {
     61                        vtable_instances.beginScope();
     62                }
     63                void leaveScope() {
     64                        vtable_instances.endScope();
     65                }
     66
     67                ObjectDecl * insert( ObjectDecl * vtableDecl ) {
     68                        std::string const & mangledName = SymTab::Mangler::mangleType( vtableDecl->type );
     69                        ObjectDecl *& value = vtable_instances[ mangledName ];
     70                        if ( value ) {
     71                                if ( vtableDecl->storageClasses.is_extern ) {
     72                                        return nullptr;
     73                                } else if ( ! value->storageClasses.is_extern ) {
     74                                        return value;
     75                                }
     76                        }
     77                        value = vtableDecl;
     78                        return nullptr;
     79                }
     80
     81                ObjectDecl * lookup( const Type * vtableType ) {
     82                        std::string const & mangledName = SymTab::Mangler::mangleType( vtableType );
     83                        const auto it = vtable_instances.find( mangledName );
     84                        return ( vtable_instances.end() == it ) ? nullptr : it->second;
     85                }
     86        };
     87
     88        class VirtualCastCore {
     89                CastExpr * cast_to_type_id( Expression * expr, int level_of_indirection ) {
     90                        Type * type = new StructInstType(
     91                                Type::Qualifiers( Type::Const ), pvt_decl );
     92                        for (int i = 0 ; i < level_of_indirection ; ++i) {
     93                                type = new PointerType( noQualifiers, type );
     94                        }
     95                        return new CastExpr( expr, type );
     96                }
     97
     98        public:
     99                VirtualCastCore() :
     100                        indexer(), vcast_decl( nullptr ), pvt_decl( nullptr )
     101                {}
     102
     103                void premutate( FunctionDecl * functionDecl );
     104                void premutate( StructDecl * structDecl );
     105                void premutate( ObjectDecl * objectDecl );
     106
     107                Expression * postmutate( VirtualCastExpr * castExpr );
     108
     109                VirtualTableMap indexer;
     110        private:
     111                FunctionDecl *vcast_decl;
     112                StructDecl *pvt_decl;
     113        };
     114
     115        void VirtualCastCore::premutate( FunctionDecl * functionDecl ) {
     116                if ( (! vcast_decl) &&
     117                     functionDecl->get_name() == "__cfavir_virtual_cast" ) {
     118                        vcast_decl = functionDecl;
     119                }
     120        }
     121
     122        void VirtualCastCore::premutate( StructDecl * structDecl ) {
     123                if ( pvt_decl || ! structDecl->has_body() ) {
     124                        return;
     125                } else if ( structDecl->get_name() == "__cfavir_type_info" ) {
     126                        pvt_decl = structDecl;
     127                }
     128        }
     129
     130        void VirtualCastCore::premutate( ObjectDecl * objectDecl ) {
     131                if ( is_type_id_object( objectDecl ) ) {
     132                        // Multiple definitions should be fine because of linkonce.
     133                        indexer.insert( objectDecl );
     134                }
     135        }
     136
     137        /// Better error locations for generated casts.
     138        CodeLocation castLocation( const VirtualCastExpr * castExpr ) {
     139                if ( castExpr->location.isSet() ) {
     140                        return castExpr->location;
     141                } else if ( castExpr->arg->location.isSet() ) {
     142                        return castExpr->arg->location;
     143                } else if ( castExpr->result->location.isSet() ) {
     144                        return castExpr->result->location;
     145                } else {
     146                        return CodeLocation();
     147                }
     148        }
     149
     150        [[noreturn]] void castError( const VirtualCastExpr * castExpr, std::string const & message ) {
     151                SemanticError( castLocation( castExpr ), message );
     152        }
     153
     154        /// Get the base type from a pointer or reference.
     155        const Type * getBaseType( const Type * type ) {
     156                if ( auto target = dynamic_cast<const PointerType *>( type ) ) {
     157                        return target->base;
     158                } else if ( auto target = dynamic_cast<const ReferenceType *>( type ) ) {
     159                        return target->base;
     160                } else {
     161                        return nullptr;
     162                }
     163        }
     164
     165        /* Attempt to follow the "head" field of the structure to get the...
     166         * Returns nullptr on error, otherwise owner must free returned node.
     167         */
     168        StructInstType * followHeadPointerType(
     169                        const StructInstType * oldType,
     170                        const std::string& fieldName,
     171                        const CodeLocation& errorLocation ) {
     172
     173                // First section of the function is all about trying to fill this variable in.
     174                StructInstType * newType = nullptr;
     175                {
     176                        const StructDecl * oldDecl = oldType->baseStruct;
     177                        assert( oldDecl );
     178
     179                        // Helper function for throwing semantic errors.
     180                        auto throwError = [&fieldName, &errorLocation, &oldDecl](const std::string& message) {
     181                                const std::string& context = "While following head pointer of " +
     182                                        oldDecl->name + " named '" + fieldName + "': ";
     183                                SemanticError( errorLocation, context + message );
     184                        };
     185
     186                        if ( oldDecl->members.empty() ) {
     187                                throwError( "Type has no fields." );
     188                        }
     189                        const Declaration * memberDecl = oldDecl->members.front();
     190                        assert( memberDecl );
     191                        const ObjectDecl * fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl );
     192                        assert( fieldDecl );
     193                        if ( fieldName != fieldDecl->name ) {
     194                                throwError( "Head field did not have expected name." );
     195                        }
     196
     197                        const Type * fieldType = fieldDecl->type;
     198                        if ( nullptr == fieldType ) {
     199                                throwError( "Could not get head field." );
     200                        }
     201                        const PointerType * ptrType = dynamic_cast<const PointerType *>( fieldType );
     202                        if ( nullptr == ptrType ) {
     203                                throwError( "First field is not a pointer type." );
     204                        }
     205                        assert( ptrType->base );
     206                        newType = dynamic_cast<StructInstType *>( ptrType->base );
     207                        if ( nullptr == newType ) {
     208                                throwError( "First field does not point to a structure type." );
     209                        }
     210                }
     211
     212                // Now we can look into copying it.
     213                newType = newType->clone();
     214                if ( ! oldType->parameters.empty() ) {
     215                        deleteAll( newType->parameters );
     216                        newType->parameters.clear();
     217                        cloneAll( oldType->parameters, newType->parameters );
     218                }
     219                return newType;
     220        }
     221
     222        /// Get the type-id type from a virtual type.
     223        StructInstType * getTypeIdType( const Type * type, const CodeLocation& errorLocation ) {
     224                const StructInstType * typeInst = dynamic_cast<const StructInstType *>( type );
     225                if ( nullptr == typeInst ) {
     226                        return nullptr;
     227                }
     228                StructInstType * tableInst =
     229                        followHeadPointerType( typeInst, "virtual_table", errorLocation );
     230                if ( nullptr == tableInst ) {
     231                        return nullptr;
     232                }
     233                StructInstType * typeIdInst =
     234                        followHeadPointerType( tableInst, "__cfavir_typeid", errorLocation );
     235                delete tableInst;
     236                return typeIdInst;
     237        }
     238
     239        Expression * VirtualCastCore::postmutate( VirtualCastExpr * castExpr ) {
     240                assertf( castExpr->result, "Virtual Cast target not found before expansion." );
     241
     242                assert( vcast_decl );
     243                assert( pvt_decl );
     244
     245                const Type * base_type = getBaseType( castExpr->result );
     246                if ( nullptr == base_type ) {
     247                        castError( castExpr, "Virtual cast target must be a pointer or reference type." );
     248                }
     249                const Type * type_id_type = getTypeIdType( base_type, castLocation( castExpr ) );
     250                if ( nullptr == type_id_type ) {
     251                        castError( castExpr, "Ill formed virtual cast target type." );
     252                }
     253                ObjectDecl * type_id = indexer.lookup( type_id_type );
     254                delete type_id_type;
     255                if ( nullptr == type_id ) {
     256                        castError( castExpr, "Virtual cast does not target a virtual type." );
     257                }
     258
     259                Expression * result = new CastExpr(
     260                        new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), {
     261                                cast_to_type_id( new AddressExpr( new VariableExpr( type_id ) ), 1 ),
     262                                cast_to_type_id( castExpr->get_arg(), 2 ),
     263                        } ),
     264                        castExpr->get_result()->clone()
     265                );
     266
     267                castExpr->set_arg( nullptr );
     268                castExpr->set_result( nullptr );
     269                delete castExpr;
     270                return result;
     271        }
    46272
    47273/// Better error locations for generated casts.
     
    268494} // namespace
    269495
     496void expandCasts( std::list< Declaration * > & translationUnit ) {
     497        PassVisitor<VirtualCastCore> translator;
     498        mutateAll( translationUnit, translator );
     499}
     500
    270501void expandCasts( ast::TranslationUnit & translationUnit ) {
    271502        ast::Pass<ExpandCastsCore>::run( translationUnit );
Note: See TracChangeset for help on using the changeset viewer.