Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Virtual/ExpandCasts.cc

    r8f910430 rc36814a  
    1010// Created On       : Mon Jul 24 13:59:00 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Jul 31 10:29:00 2020
    13 // Update Count     : 4
     12// Last Modified On : Thu Aug 11 12:06:00 2022
     13// Update Count     : 5
    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"
    2225#include "Common/PassVisitor.h"    // for PassVisitor
    2326#include "Common/ScopedMap.h"      // for ScopedMap
     
    3235namespace Virtual {
    3336
    34 static bool is_prefix( const std::string & prefix, const std::string& entire ) {
     37namespace {
     38
     39bool is_prefix( const std::string & prefix, const std::string& entire ) {
    3540        size_t const p_size = prefix.size();
    3641        return (p_size < entire.size() && prefix == entire.substr(0, p_size));
    3742}
    3843
    39 static bool is_type_id_object( const ObjectDecl * objectDecl ) {
     44bool is_type_id_object( const ObjectDecl * objectDecl ) {
    4045        const std::string & objectName = objectDecl->name;
    4146        return is_prefix( "__cfatid_", objectName );
     47}
     48
     49bool is_type_id_object( const ast::ObjectDecl * decl ) {
     50        return is_prefix( "__cfatid_", decl->name );
    4251}
    4352
     
    124133                }
    125134        }
    126 
    127         namespace {
    128135
    129136        /// Better error locations for generated casts.
     
    229236        }
    230237
    231         } // namespace
    232 
    233238        Expression * VirtualCastCore::postmutate( VirtualCastExpr * castExpr ) {
    234239                assertf( castExpr->result, "Virtual Cast target not found before expansion." );
     
    265270        }
    266271
    267         void expandCasts( std::list< Declaration * > & translationUnit ) {
    268                 PassVisitor<VirtualCastCore> translator;
    269                 mutateAll( translationUnit, translator );
    270         }
    271 }
     272/// Better error locations for generated casts.
     273// TODO: Does the improved distribution of code locations make this unneeded?
     274CodeLocation 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();
     281        }
     282}
     283
     284[[noreturn]] void castError( ast::VirtualCastExpr const * castExpr, std::string const & message ) {
     285        SemanticError( castLocation( castExpr ), message );
     286}
     287
     288class TypeIdTable final {
     289        ScopedMap<std::string, ast::ObjectDecl const *> instances;
     290public:
     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
     319struct 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
     334void ExpandCastsCore::previsit( ast::FunctionDecl const * decl ) {
     335        if ( !vcast_decl && "__cfavir_virtual_cast" == decl->name ) {
     336                vcast_decl = decl;
     337        }
     338}
     339
     340void ExpandCastsCore::previsit( ast::StructDecl const * decl ) {
     341        if ( !info_decl && decl->body && "__cfavir_type_info" == decl->name ) {
     342                info_decl = decl;
     343        }
     344}
     345
     346void 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.
     354ast::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.
     365ast::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.
     381ast::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.
     425ast::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
     442ast::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
     485ast::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
     497void expandCasts( std::list< Declaration * > & translationUnit ) {
     498        PassVisitor<VirtualCastCore> translator;
     499        mutateAll( translationUnit, translator );
     500}
     501
     502void 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.