Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Virtual/ExpandCasts.cc

    rccbc65c 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 {
    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 ast::StructInstType * polyCopy(
    365                 ast::StructInstType const * oldType,
    366                 ast::StructInstType const * newType ) {
    367         assert( oldType->params.size() == newType->params.size() );
    368         ast::StructInstType * retType = ast::deepCopy( newType );
    369         if ( ! oldType->params.empty() ) {
    370                 retType->params.clear();
    371                 for ( auto oldParams : oldType->params ) {
    372                         retType->params.push_back( ast::deepCopy( oldParams ) );
    373                 }
    374         }
    375         return retType;
    376 }
    377 
    378 /// Follow the "head" field of the structure to get the type that is pointed
    379 /// to by that field.
    380 ast::StructInstType const * followHeadPointerType(
    381                 CodeLocation const & errorLocation,
    382                 ast::StructInstType const * oldType,
    383                 std::string const & fieldName ) {
    384         ast::StructDecl const * oldDecl = oldType->base;
    385         assert( oldDecl );
    386 
    387         // Helper function for throwing semantic errors.
    388         auto throwError = [&fieldName, &errorLocation, &oldDecl](
    389                         std::string const & message ) {
    390                 std::string const & context = "While following head pointer of " +
    391                         oldDecl->name + " named '" + fieldName + "': ";
    392                 SemanticError( errorLocation, context + message );
    393         };
    394 
    395         if ( oldDecl->members.empty() ) {
    396                 throwError( "Type has no fields." );
    397         }
    398         ast::ptr<ast::Decl> const & memberDecl = oldDecl->members.front();
    399         assert( memberDecl );
    400         ast::ObjectDecl const * fieldDecl = memberDecl.as<ast::ObjectDecl>();
    401         assert( fieldDecl );
    402         if ( fieldName != fieldDecl->name ) {
    403                 throwError( "Head field did not have expected name." );
    404         }
    405 
    406         ast::ptr<ast::Type> const & fieldType = fieldDecl->type;
    407         if ( nullptr == fieldType ) {
    408                 throwError( "Could not get head field." );
    409         }
    410         auto ptrType = fieldType.as<ast::PointerType>();
    411         if ( nullptr == ptrType ) {
    412                 throwError( "First field is not a pointer type." );
    413         }
    414         assert( ptrType->base );
    415         auto newType = ptrType->base.as<ast::StructInstType>();
    416         if ( nullptr == newType ) {
    417                 throwError( "First field does not point to a structure type." );
    418         }
    419 
    420         return polyCopy( oldType, newType );
    421 }
    422 
    423 /// Get the type-id type from a virtual type.
    424 ast::StructInstType const * getTypeIdType(
    425                 CodeLocation const & errorLocation,
    426                 ast::Type const * type ) {
    427         auto typeInst = dynamic_cast<ast::StructInstType const *>( type );
    428         if ( nullptr == typeInst ) {
    429                 return nullptr;
    430         }
    431         ast::ptr<ast::StructInstType> tableInst =
    432                 followHeadPointerType( errorLocation, typeInst, "virtual_table" );
    433         if ( nullptr == tableInst ) {
    434                 return nullptr;
    435         }
    436         ast::StructInstType const * typeIdInst =
    437                 followHeadPointerType( errorLocation, tableInst, "__cfavir_typeid" );
    438         return typeIdInst;
    439 }
    440 
    441 ast::Expr const * ExpandCastsCore::postvisit(
    442                 ast::VirtualCastExpr const * expr ) {
    443         assertf( expr->result, "Virtual cast target not found before expansion." );
    444 
    445         assert( vcast_decl );
    446         assert( info_decl );
    447 
    448         ast::Type const * base_type = getBaseType( expr->result );
    449         if ( nullptr == base_type ) {
    450                 castError( expr, "Virtual cast target must be a pointer or reference type." );
    451         }
    452         ast::StructInstType const * type_id_type =
    453                         getTypeIdType( castLocation( expr ), base_type );
    454         if ( nullptr == type_id_type ) {
    455                 castError( expr, "Ill formed virtual cast target type." );
    456         }
    457         ast::ObjectDecl const * type_id = symtab.lookup( type_id_type );
    458         if ( nullptr == type_id ) {
    459                 // I'm trying to give a different error for polymorpic types as
    460                 // different things can go wrong there.
    461                 if ( type_id_type->params.empty() ) {
    462                         castError( expr, "Virtual cast does not target a virtual type." );
    463                 } else {
    464                         castError( expr, "Virtual cast does not target a type with a "
    465                                 "type id (possible missing virtual table)." );
    466                 }
    467         }
    468 
    469         return new ast::CastExpr( expr->location,
    470                 new ast::ApplicationExpr( expr->location,
    471                         ast::VariableExpr::functionPointer( expr->location, vcast_decl ),
    472                         {
    473                                 cast_to_type_id(
    474                                         new ast::AddressExpr( expr->location,
    475                                                 new ast::VariableExpr( expr->location, type_id ) ),
    476                                         1 ),
    477                                 cast_to_type_id( expr->arg, 2 ),
    478                         }
    479                 ),
    480                 ast::deepCopy( expr->result )
    481         );
    482 }
    483 
    484 ast::CastExpr const * ExpandCastsCore::cast_to_type_id(
    485                 ast::Expr const * expr, unsigned int level_of_indirection ) {
    486         assert( info_decl );
    487         ast::Type * type = new ast::StructInstType( info_decl, ast::CV::Const );
    488         for ( unsigned int i = 0 ; i < level_of_indirection ; ++i ) {
    489                 type = new ast::PointerType( type );
    490         }
    491         return new ast::CastExpr( expr->location, expr, type );
    492 }
    493 
    494 } // namespace
    495 
    496 void expandCasts( std::list< Declaration * > & translationUnit ) {
    497         PassVisitor<VirtualCastCore> translator;
    498         mutateAll( translationUnit, translator );
    499 }
    500 
    501 void expandCasts( ast::TranslationUnit & translationUnit ) {
    502         ast::Pass<ExpandCastsCore>::run( translationUnit );
    503 }
    504 
    505 } // namespace Virtual
Note: See TracChangeset for help on using the changeset viewer.