Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Virtual/ExpandCasts.cc

    rb91bfde r6dba8755  
    3232namespace Virtual {
    3333
    34 static bool is_prefix( const std::string & prefix, const std::string& entire ) {
    35         size_t const p_size = prefix.size();
    36         return (p_size < entire.size() && prefix == entire.substr(0, p_size));
    37 }
    38 
    39 static bool is_type_id_object( const ObjectDecl * objectDecl ) {
    40         const std::string & objectName = objectDecl->name;
    41         return is_prefix( "__cfatid_", objectName );
    42 }
    43 
    4434        // Indented until the new ast code gets added.
    4535
     
    7666        };
    7767
     68        /* Currently virtual depends on the rather brittle name matching between
     69         * a (strict/explicate) virtual type, its vtable type and the vtable
     70         * instance.
     71         * A stronger implementation, would probably keep track of those triads
     72         * and use that information to create better error messages.
     73         */
     74
     75        namespace {
     76
     77        std::string get_vtable_name( std::string const & name ) {
     78                return name + "_vtable";
     79        }
     80
     81        std::string get_vtable_inst_name( std::string const & name ) {
     82                return std::string("_") + get_vtable_name( name ) + "_instance";
     83        }
     84
     85        std::string get_vtable_name_root( std::string const & name ) {
     86                return name.substr(0, name.size() - 7 );
     87        }
     88
     89        std::string get_vtable_inst_name_root( std::string const & name ) {
     90                return get_vtable_name_root( name.substr(1, name.size() - 10 ) );
     91        }
     92
     93        bool is_vtable_inst_name( std::string const & name ) {
     94                return 17 < name.size() &&
     95                        name == get_vtable_inst_name( get_vtable_inst_name_root( name ) );
     96        }
     97
     98        } // namespace
     99
    78100        class VirtualCastCore {
    79                 CastExpr * cast_to_type_id( Expression * expr, int level_of_indirection ) {
     101                Type * pointer_to_pvt(int level_of_indirection) {
    80102                        Type * type = new StructInstType(
    81103                                Type::Qualifiers( Type::Const ), pvt_decl );
     
    83105                                type = new PointerType( noQualifiers, type );
    84106                        }
    85                         return new CastExpr( expr, type );
     107                        return type;
    86108                }
    87109
     
    119141
    120142        void VirtualCastCore::premutate( ObjectDecl * objectDecl ) {
    121                 if ( is_type_id_object( objectDecl ) ) {
    122                         // Multiple definitions should be fine because of linkonce.
    123                         indexer.insert( objectDecl );
     143                if ( is_vtable_inst_name( objectDecl->get_name() ) ) {
     144                        if ( ObjectDecl * existing = indexer.insert( objectDecl ) ) {
     145                                std::string msg = "Repeated instance of virtual table, original found at: ";
     146                                msg += existing->location.filename;
     147                                msg += ":" + toString( existing->location.first_line );
     148                                SemanticError( objectDecl->location, msg );
     149                        }
    124150                }
    125151        }
     
    144170        }
    145171
    146         /// Get the base type from a pointer or reference.
    147         const Type * getBaseType( const Type * type ) {
    148                 if ( auto target = dynamic_cast<const PointerType *>( type ) ) {
    149                         return target->base;
    150                 } else if ( auto target = dynamic_cast<const ReferenceType *>( type ) ) {
    151                         return target->base;
     172        /// Get the virtual table type used in a virtual cast.
     173        Type * getVirtualTableType( const VirtualCastExpr * castExpr ) {
     174                const Type * objectType;
     175                if ( auto target = dynamic_cast<const PointerType *>( castExpr->result ) ) {
     176                        objectType = target->base;
     177                } else if ( auto target = dynamic_cast<const ReferenceType *>( castExpr->result ) ) {
     178                        objectType = target->base;
    152179                } else {
    153                         return nullptr;
    154                 }
    155         }
    156 
    157         /* Attempt to follow the "head" field of the structure to get the...
    158          * Returns nullptr on error, otherwise owner must free returned node.
    159          */
    160         StructInstType * followHeadPointerType(
    161                         const StructInstType * oldType,
    162                         const std::string& fieldName,
    163                         const CodeLocation& errorLocation ) {
    164 
    165                 // First section of the function is all about trying to fill this variable in.
    166                 StructInstType * newType = nullptr;
    167                 {
    168                         const StructDecl * oldDecl = oldType->baseStruct;
    169                         assert( oldDecl );
    170 
    171                         // Helper function for throwing semantic errors.
    172                         auto throwError = [&fieldName, &errorLocation, &oldDecl](const std::string& message) {
    173                                 const std::string& context = "While following head pointer of " +
    174                                         oldDecl->name + " named '" + fieldName + "': ";
    175                                 SemanticError( errorLocation, context + message );
    176                         };
    177 
    178                         if ( oldDecl->members.empty() ) {
    179                                 throwError( "Type has no fields." );
    180                         }
    181                         const Declaration * memberDecl = oldDecl->members.front();
     180                        castError( castExpr, "Virtual cast type must be a pointer or reference type." );
     181                }
     182                assert( objectType );
     183
     184                const StructInstType * structType = dynamic_cast<const StructInstType *>( objectType );
     185                if ( nullptr == structType ) {
     186                        castError( castExpr, "Virtual cast type must refer to a structure type." );
     187                }
     188                const StructDecl * structDecl = structType->baseStruct;
     189                assert( structDecl );
     190
     191                const ObjectDecl * fieldDecl = nullptr;
     192                if ( 0 < structDecl->members.size() ) {
     193                        const Declaration * memberDecl = structDecl->members.front();
    182194                        assert( memberDecl );
    183                         const ObjectDecl * fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl );
    184                         assert( fieldDecl );
    185                         if ( fieldName != fieldDecl->name ) {
    186                                 throwError( "Head field did not have expected name." );
    187                         }
    188 
    189                         const Type * fieldType = fieldDecl->type;
    190                         if ( nullptr == fieldType ) {
    191                                 throwError( "Could not get head field." );
    192                         }
    193                         const PointerType * ptrType = dynamic_cast<const PointerType *>( fieldType );
    194                         if ( nullptr == ptrType ) {
    195                                 throwError( "First field is not a pointer type." );
    196                         }
    197                         assert( ptrType->base );
    198                         newType = dynamic_cast<StructInstType *>( ptrType->base );
    199                         if ( nullptr == newType ) {
    200                                 throwError( "First field does not point to a structure type." );
    201                         }
    202                 }
    203 
    204                 // Now we can look into copying it.
    205                 newType = newType->clone();
    206                 if ( ! oldType->parameters.empty() ) {
    207                         deleteAll( newType->parameters );
    208                         newType->parameters.clear();
    209                         cloneAll( oldType->parameters, newType->parameters );
    210                 }
    211                 return newType;
    212         }
    213 
    214         /// Get the type-id type from a virtual type.
    215         StructInstType * getTypeIdType( const Type * type, const CodeLocation& errorLocation ) {
    216                 const StructInstType * typeInst = dynamic_cast<const StructInstType *>( type );
    217                 if ( nullptr == typeInst ) {
    218                         return nullptr;
    219                 }
    220                 StructInstType * tableInst =
    221                         followHeadPointerType( typeInst, "virtual_table", errorLocation );
    222                 if ( nullptr == tableInst ) {
    223                         return nullptr;
    224                 }
    225                 StructInstType * typeIdInst =
    226                         followHeadPointerType( tableInst, "__cfavir_typeid", errorLocation );
    227                 delete tableInst;
    228                 return typeIdInst;
     195                        fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl );
     196                        if ( fieldDecl && fieldDecl->name != "virtual_table" ) {
     197                                fieldDecl = nullptr;
     198                        }
     199                }
     200                if ( nullptr == fieldDecl ) {
     201                        castError( castExpr, "Virtual cast type must have a leading virtual_table field." );
     202                }
     203                const PointerType * fieldType = dynamic_cast<const PointerType *>( fieldDecl->type );
     204                if ( nullptr == fieldType ) {
     205                        castError( castExpr, "Virtual cast type virtual_table field is not a pointer." );
     206                }
     207                assert( fieldType->base );
     208                auto virtualStructType = dynamic_cast<const StructInstType *>( fieldType->base );
     209                assert( virtualStructType );
     210
     211                // Here is the type, but if it is polymorphic it will have lost information.
     212                // (Always a clone so that it may always be deleted.)
     213                StructInstType * virtualType = virtualStructType->clone();
     214                if ( ! structType->parameters.empty() ) {
     215                        deleteAll( virtualType->parameters );
     216                        virtualType->parameters.clear();
     217                        cloneAll( structType->parameters, virtualType->parameters );
     218                }
     219                return virtualType;
    229220        }
    230221
     
    237228                assert( pvt_decl );
    238229
    239                 const Type * base_type = getBaseType( castExpr->result );
    240                 if ( nullptr == base_type ) {
    241                         castError( castExpr, "Virtual cast target must be a pointer or reference type." );
    242                 }
    243                 const Type * type_id_type = getTypeIdType( base_type, castLocation( castExpr ) );
    244                 if ( nullptr == type_id_type ) {
    245                         castError( castExpr, "Ill formed virtual cast target type." );
    246                 }
    247                 ObjectDecl * type_id = indexer.lookup( type_id_type );
    248                 delete type_id_type;
    249                 if ( nullptr == type_id ) {
    250                         castError( castExpr, "Virtual cast does not target a virtual type." );
     230                const Type * vtable_type = getVirtualTableType( castExpr );
     231                ObjectDecl * table = indexer.lookup( vtable_type );
     232                if ( nullptr == table ) {
     233                        SemanticError( castLocation( castExpr ),
     234                                "Could not find virtual table instance." );
    251235                }
    252236
    253237                Expression * result = new CastExpr(
    254238                        new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), {
    255                                 cast_to_type_id( new AddressExpr( new VariableExpr( type_id ) ), 1 ),
    256                                 cast_to_type_id( castExpr->get_arg(), 2 ),
     239                                        new CastExpr(
     240                                                new AddressExpr( new VariableExpr( table ) ),
     241                                                pointer_to_pvt(1)
     242                                        ),
     243                                        new CastExpr(
     244                                                castExpr->get_arg(),
     245                                                pointer_to_pvt(2)
     246                                        )
    257247                        } ),
    258248                        castExpr->get_result()->clone()
     
    262252                castExpr->set_result( nullptr );
    263253                delete castExpr;
     254                delete vtable_type;
    264255                return result;
    265256        }
Note: See TracChangeset for help on using the changeset viewer.