Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Virtual/ExpandCasts.cc

    rc36814a r8f910430  
    1010// Created On       : Mon Jul 24 13:59:00 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Aug 11 12:06:00 2022
    13 // Update Count     : 5
     12// Last Modified On : Fri Jul 31 10:29:00 2020
     13// Update Count     : 4
    1414//
    1515
     
    2020#include <string>                  // for string, allocator, operator==, ope...
    2121
    22 #include "AST/Decl.hpp"
    23 #include "AST/Expr.hpp"
    24 #include "AST/Pass.hpp"
    2522#include "Common/PassVisitor.h"    // for PassVisitor
    2623#include "Common/ScopedMap.h"      // for ScopedMap
     
    3532namespace Virtual {
    3633
    37 namespace {
    38 
    39 bool is_prefix( const std::string & prefix, const std::string& entire ) {
     34static bool is_prefix( const std::string & prefix, const std::string& entire ) {
    4035        size_t const p_size = prefix.size();
    4136        return (p_size < entire.size() && prefix == entire.substr(0, p_size));
    4237}
    4338
    44 bool is_type_id_object( const ObjectDecl * objectDecl ) {
     39static bool is_type_id_object( const ObjectDecl * objectDecl ) {
    4540        const std::string & objectName = objectDecl->name;
    4641        return is_prefix( "__cfatid_", objectName );
    47 }
    48 
    49 bool is_type_id_object( const ast::ObjectDecl * decl ) {
    50         return is_prefix( "__cfatid_", decl->name );
    5142}
    5243
     
    133124                }
    134125        }
     126
     127        namespace {
    135128
    136129        /// Better error locations for generated casts.
     
    236229        }
    237230
     231        } // namespace
     232
    238233        Expression * VirtualCastCore::postmutate( VirtualCastExpr * castExpr ) {
    239234                assertf( castExpr->result, "Virtual Cast target not found before expansion." );
     
    270265        }
    271266
    272 /// Better error locations for generated casts.
    273 // TODO: Does the improved distribution of code locations make this unneeded?
    274 CodeLocation castLocation( const ast::VirtualCastExpr * castExpr ) {
    275         if ( castExpr->location.isSet() ) {
    276                 return castExpr->location;
    277         } else if ( castExpr->arg->location.isSet() ) {
    278                 return castExpr->arg->location;
    279         } else {
    280                 return CodeLocation();
     267        void expandCasts( std::list< Declaration * > & translationUnit ) {
     268                PassVisitor<VirtualCastCore> translator;
     269                mutateAll( translationUnit, translator );
    281270        }
    282271}
    283 
    284 [[noreturn]] void castError( ast::VirtualCastExpr const * castExpr, std::string const & message ) {
    285         SemanticError( castLocation( castExpr ), message );
    286 }
    287 
    288 class TypeIdTable final {
    289         ScopedMap<std::string, ast::ObjectDecl const *> instances;
    290 public:
    291         void enterScope() { instances.beginScope(); }
    292         void leaveScope() { instances.endScope(); }
    293 
    294         // Attempt to insert an instance into the map. If there is a conflict,
    295         // returns the previous declaration for error messages.
    296         ast::ObjectDecl const * insert( ast::ObjectDecl const * typeIdDecl ) {
    297                 std::string const & mangledName =
    298                                 Mangle::mangle( typeIdDecl->type, Mangle::typeMode() );
    299                 ast::ObjectDecl const *& value = instances[ mangledName ];
    300                 if ( value ) {
    301                         if ( typeIdDecl->storage.is_extern ) {
    302                                 return nullptr;
    303                         } else if ( !value->storage.is_extern ) {
    304                                 return value;
    305                         }
    306                 }
    307                 value = typeIdDecl;
    308                 return nullptr;
    309         }
    310 
    311         ast::ObjectDecl const * lookup( ast::Type const * typeIdType ) {
    312                 std::string const & mangledName =
    313                                 Mangle::mangle( typeIdType, Mangle::typeMode() );
    314                 auto const it = instances.find( mangledName );
    315                 return ( instances.end() == it ) ? nullptr : it->second;
    316         }
    317 };
    318 
    319 struct ExpandCastsCore final {
    320         void previsit( ast::FunctionDecl const * decl );
    321         void previsit( ast::StructDecl const * decl );
    322         void previsit( ast::ObjectDecl const * decl );
    323         ast::Expr const * postvisit( ast::VirtualCastExpr const * expr );
    324 
    325         ast::CastExpr const * cast_to_type_id(
    326                 ast::Expr const * expr, unsigned int level_of_indirection );
    327 
    328         ast::FunctionDecl const * vcast_decl = nullptr;
    329         ast::StructDecl const * info_decl = nullptr;
    330 
    331         TypeIdTable symtab;
    332 };
    333 
    334 void ExpandCastsCore::previsit( ast::FunctionDecl const * decl ) {
    335         if ( !vcast_decl && "__cfavir_virtual_cast" == decl->name ) {
    336                 vcast_decl = decl;
    337         }
    338 }
    339 
    340 void ExpandCastsCore::previsit( ast::StructDecl const * decl ) {
    341         if ( !info_decl && decl->body && "__cfavir_type_info" == decl->name ) {
    342                 info_decl = decl;
    343         }
    344 }
    345 
    346 void ExpandCastsCore::previsit( ast::ObjectDecl const * decl ) {
    347         if ( is_type_id_object( decl ) ) {
    348                 // Multiple definitions should be fine because of linkonce.
    349                 symtab.insert( decl );
    350         }
    351 }
    352 
    353 /// Get the base type from a pointer or reference.
    354 ast::Type const * getBaseType( ast::ptr<ast::Type> const & type ) {
    355         if ( auto target = type.as<ast::PointerType>() ) {
    356                 return target->base.get();
    357         } else if ( auto target = type.as<ast::ReferenceType>() ) {
    358                 return target->base.get();
    359         } else {
    360                 return nullptr;
    361         }
    362 }
    363 
    364 /// Copy newType, but give the copy the params of the oldType.
    365 ast::StructInstType * polyCopy(
    366                 ast::StructInstType const * oldType,
    367                 ast::StructInstType const * newType ) {
    368         assert( oldType->params.size() == newType->params.size() );
    369         ast::StructInstType * retType = ast::deepCopy( newType );
    370         if ( ! oldType->params.empty() ) {
    371                 retType->params.clear();
    372                 for ( auto oldParams : oldType->params ) {
    373                         retType->params.push_back( ast::deepCopy( oldParams ) );
    374                 }
    375         }
    376         return retType;
    377 }
    378 
    379 /// Follow the "head" field of the structure to get the type that is pointed
    380 /// to by that field.
    381 ast::StructInstType const * followHeadPointerType(
    382                 CodeLocation const & errorLocation,
    383                 ast::StructInstType const * oldType,
    384                 std::string const & fieldName ) {
    385         ast::StructDecl const * oldDecl = oldType->base;
    386         assert( oldDecl );
    387 
    388         // Helper function for throwing semantic errors.
    389         auto throwError = [&fieldName, &errorLocation, &oldDecl](
    390                         std::string const & message ) {
    391                 std::string const & context = "While following head pointer of " +
    392                         oldDecl->name + " named '" + fieldName + "': ";
    393                 SemanticError( errorLocation, context + message );
    394         };
    395 
    396         if ( oldDecl->members.empty() ) {
    397                 throwError( "Type has no fields." );
    398         }
    399         ast::ptr<ast::Decl> const & memberDecl = oldDecl->members.front();
    400         assert( memberDecl );
    401         ast::ObjectDecl const * fieldDecl = memberDecl.as<ast::ObjectDecl>();
    402         assert( fieldDecl );
    403         if ( fieldName != fieldDecl->name ) {
    404                 throwError( "Head field did not have expected name." );
    405         }
    406 
    407         ast::ptr<ast::Type> const & fieldType = fieldDecl->type;
    408         if ( nullptr == fieldType ) {
    409                 throwError( "Could not get head field." );
    410         }
    411         auto ptrType = fieldType.as<ast::PointerType>();
    412         if ( nullptr == ptrType ) {
    413                 throwError( "First field is not a pointer type." );
    414         }
    415         assert( ptrType->base );
    416         auto newType = ptrType->base.as<ast::StructInstType>();
    417         if ( nullptr == newType ) {
    418                 throwError( "First field does not point to a structure type." );
    419         }
    420 
    421         return polyCopy( oldType, newType );
    422 }
    423 
    424 /// Get the type-id type from a virtual type.
    425 ast::StructInstType const * getTypeIdType(
    426                 CodeLocation const & errorLocation,
    427                 ast::Type const * type ) {
    428         auto typeInst = dynamic_cast<ast::StructInstType const *>( type );
    429         if ( nullptr == typeInst ) {
    430                 return nullptr;
    431         }
    432         ast::ptr<ast::StructInstType> tableInst =
    433                 followHeadPointerType( errorLocation, typeInst, "virtual_table" );
    434         if ( nullptr == tableInst ) {
    435                 return nullptr;
    436         }
    437         ast::StructInstType const * typeIdInst =
    438                 followHeadPointerType( errorLocation, tableInst, "__cfavir_typeid" );
    439         return typeIdInst;
    440 }
    441 
    442 ast::Expr const * ExpandCastsCore::postvisit(
    443                 ast::VirtualCastExpr const * expr ) {
    444         assertf( expr->result, "Virtual cast target not found before expansion." );
    445 
    446         assert( vcast_decl );
    447         assert( info_decl );
    448 
    449         ast::Type const * base_type = getBaseType( expr->result );
    450         if ( nullptr == base_type ) {
    451                 castError( expr, "Virtual cast target must be a pointer or reference type." );
    452         }
    453         ast::StructInstType const * type_id_type =
    454                         getTypeIdType( castLocation( expr ), base_type );
    455         if ( nullptr == type_id_type ) {
    456                 castError( expr, "Ill formed virtual cast target type." );
    457         }
    458         ast::ObjectDecl const * type_id = symtab.lookup( type_id_type );
    459         if ( nullptr == type_id ) {
    460                 // I'm trying to give a different error for polymorpic types as
    461                 // different things can go wrong there.
    462                 if ( type_id_type->params.empty() ) {
    463                         castError( expr, "Virtual cast does not target a virtual type." );
    464                 } else {
    465                         castError( expr, "Virtual cast does not target a type with a "
    466                                 "type id (possible missing virtual table)." );
    467                 }
    468         }
    469 
    470         return new ast::CastExpr( expr->location,
    471                 new ast::ApplicationExpr( expr->location,
    472                         ast::VariableExpr::functionPointer( expr->location, vcast_decl ),
    473                         {
    474                                 cast_to_type_id(
    475                                         new ast::AddressExpr( expr->location,
    476                                                 new ast::VariableExpr( expr->location, type_id ) ),
    477                                         1 ),
    478                                 cast_to_type_id( expr->arg, 2 ),
    479                         }
    480                 ),
    481                 ast::deepCopy( expr->result )
    482         );
    483 }
    484 
    485 ast::CastExpr const * ExpandCastsCore::cast_to_type_id(
    486                 ast::Expr const * expr, unsigned int level_of_indirection ) {
    487         assert( info_decl );
    488         ast::Type * type = new ast::StructInstType( info_decl, ast::CV::Const );
    489         for ( unsigned int i = 0 ; i < level_of_indirection ; ++i ) {
    490                 type = new ast::PointerType( type );
    491         }
    492         return new ast::CastExpr( expr->location, expr, type );
    493 }
    494 
    495 } // namespace
    496 
    497 void expandCasts( std::list< Declaration * > & translationUnit ) {
    498         PassVisitor<VirtualCastCore> translator;
    499         mutateAll( translationUnit, translator );
    500 }
    501 
    502 void expandCasts( ast::TranslationUnit & translationUnit ) {
    503         ast::Pass<ExpandCastsCore>::run( translationUnit );
    504 }
    505 
    506 } // namespace Virtual
Note: See TracChangeset for help on using the changeset viewer.