// // Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo // // The contents of this file are covered under the licence agreement in the // file "LICENCE" distributed with Cforall. // // ExpandCasts.cc -- // // Author : Andrew Beach // Created On : Mon Jul 24 13:59:00 2017 // Last Modified By : Andrew Beach // Last Modified On : Tus Aug 2 14:59:00 2017 // Update Count : 1 // #include "ExpandCasts.h" #include // for assert, assertf #include // for back_inserter, inserter #include // for map, _Rb_tree_iterator, map<>::ite... #include // for string, allocator, operator==, ope... #include // for pair #include "Common/PassVisitor.h" // for PassVisitor #include "Common/SemanticError.h" // for SemanticError #include "SynTree/Declaration.h" // for ObjectDecl, StructDecl, FunctionDecl #include "SynTree/Expression.h" // for VirtualCastExpr, CastExpr, Address... #include "SynTree/Mutator.h" // for mutateAll #include "SynTree/Type.h" // for Type, PointerType, StructInstType #include "SynTree/Visitor.h" // for acceptAll namespace Virtual { /* Currently virtual depends on the rather brittle name matching between * a (strict/explicate) virtual type, its vtable type and the vtable * instance. * A stronger implementation, would probably keep track of those triads * and use that information to create better error messages. */ std::string get_vtable_name( std::string const & name ) { return name + "_vtable"; } std::string get_vtable_inst_name( std::string const & name ) { return std::string("_") + get_vtable_name( name ) + "_instance"; } std::string get_vtable_name_root( std::string const & name ) { return name.substr(0, name.size() - 7 ); } std::string get_vtable_inst_name_root( std::string const & name ) { return get_vtable_name_root( name.substr(1, name.size() - 10 ) ); } bool is_vtable_name( std::string const & name ) { return (name.substr( name.size() - 7 ) == "_vtable" ); } bool is_vtable_inst_name( std::string const & name ) { return 17 < name.size() && name == get_vtable_inst_name( get_vtable_inst_name_root( name ) ); } class VirtualCastCore { std::map vtable_instances; FunctionDecl *vcast_decl; StructDecl *pvt_decl; Type * pointer_to_pvt(int level_of_indirection) { Type * type = new StructInstType( Type::Qualifiers( Type::Const ), pvt_decl ); for (int i = 0 ; i < level_of_indirection ; ++i) { type = new PointerType( noQualifiers, type ); } return type; } public: VirtualCastCore() : vtable_instances(), vcast_decl( nullptr ), pvt_decl( nullptr ) {} void premutate( FunctionDecl * functionDecl ); void premutate( StructDecl * structDecl ); void premutate( ObjectDecl * objectDecl ); Expression * postmutate( VirtualCastExpr * castExpr ); }; void VirtualCastCore::premutate( FunctionDecl * functionDecl ) { if ( (! vcast_decl) && functionDecl->get_name() == "__cfa__virtual_cast" ) { vcast_decl = functionDecl; } } void VirtualCastCore::premutate( StructDecl * structDecl ) { if ( pvt_decl || ! structDecl->has_body() ) { return; } else if ( structDecl->get_name() == "__cfa__parent_vtable" ) { pvt_decl = structDecl; } } void VirtualCastCore::premutate( ObjectDecl * objectDecl ) { if ( is_vtable_inst_name( objectDecl->get_name() ) ) { vtable_instances[objectDecl->get_name()] = objectDecl; } } Expression * VirtualCastCore::postmutate( VirtualCastExpr * castExpr ) { assertf( castExpr->get_result(), "Virtual Cast target not found before expansion." ); assert( vcast_decl ); assert( pvt_decl ); // May only cast to a pointer or reference type. // A earlier validation should give a syntax error, this is // just to make sure errors don't creep during translation. // Move to helper with more detailed error messages. PointerType * target_type = dynamic_cast( castExpr->get_result() ); assert( target_type ); StructInstType * target_struct = dynamic_cast( target_type->get_base() ); assert( target_struct ); StructDecl * target_decl = target_struct->get_baseStruct(); std::map::iterator found = vtable_instances.find( get_vtable_inst_name( target_decl->get_name() ) ); if ( vtable_instances.end() == found ) { assertf( false, "virtual table instance not found." ); } ObjectDecl * table = found->second; Expression * result = new CastExpr( //new ApplicationExpr( //new AddressExpr( new VariableExpr( vcast_decl ) ), //new CastExpr( new VariableExpr( vcast_decl ), // new PointerType( noQualifiers, // vcast_decl->get_type()->clone() // ) // ), new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), { new CastExpr( new AddressExpr( new VariableExpr( table ) ), pointer_to_pvt(1) ), new CastExpr( castExpr->get_arg(), pointer_to_pvt(2) ) } ), castExpr->get_result()->clone() ); castExpr->set_arg( nullptr ); castExpr->set_result( nullptr ); delete castExpr; return result; } void expandCasts( std::list< Declaration * > & translationUnit ) { PassVisitor translator; mutateAll( translationUnit, translator ); } }