Changeset c6b4432 for src/Virtual
- Timestamp:
- Nov 8, 2023, 2:01:11 PM (23 months ago)
- Branches:
- master
- Children:
- 3e4bf0d, f5ec35a
- Parents:
- 790d835
- Location:
- src/Virtual
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Virtual/ExpandCasts.cc
r790d835 rc6b4432 24 24 #include "AST/Expr.hpp" 25 25 #include "AST/Pass.hpp" 26 #include "Common/PassVisitor.h" // for PassVisitor27 26 #include "Common/ScopedMap.h" // for ScopedMap 28 27 #include "Common/SemanticError.h" // for SemanticError 29 28 #include "SymTab/Mangler.h" // for mangleType 30 #include "SynTree/Declaration.h" // for ObjectDecl, StructDecl, FunctionDecl31 #include "SynTree/Expression.h" // for VirtualCastExpr, CastExpr, Address...32 #include "SynTree/Mutator.h" // for mutateAll33 #include "SynTree/Type.h" // for Type, PointerType, StructInstType34 #include "SynTree/Visitor.h" // for acceptAll35 29 36 30 namespace Virtual { … … 43 37 } 44 38 45 bool is_type_id_object( const ObjectDecl * objectDecl ) {46 const std::string & objectName = objectDecl->name;47 return is_prefix( "__cfatid_", objectName );48 }49 50 39 bool is_type_id_object( const ast::ObjectDecl * decl ) { 51 40 return is_prefix( "__cfatid_", decl->name ); … … 55 44 56 45 /// Maps virtual table types the instance for that type. 57 class VirtualTableMap final {58 ScopedMap<std::string, ObjectDecl *> vtable_instances;59 public:60 void enterScope() {61 vtable_instances.beginScope();62 }63 void leaveScope() {64 vtable_instances.endScope();65 }66 67 ObjectDecl * insert( ObjectDecl * vtableDecl ) {68 std::string const & mangledName = SymTab::Mangler::mangleType( vtableDecl->type );69 ObjectDecl *& value = vtable_instances[ mangledName ];70 if ( value ) {71 if ( vtableDecl->storageClasses.is_extern ) {72 return nullptr;73 } else if ( ! value->storageClasses.is_extern ) {74 return value;75 }76 }77 value = vtableDecl;78 return nullptr;79 }80 81 ObjectDecl * lookup( const Type * vtableType ) {82 std::string const & mangledName = SymTab::Mangler::mangleType( vtableType );83 const auto it = vtable_instances.find( mangledName );84 return ( vtable_instances.end() == it ) ? nullptr : it->second;85 }86 };87 88 class VirtualCastCore {89 CastExpr * cast_to_type_id( Expression * expr, int level_of_indirection ) {90 Type * type = new StructInstType(91 Type::Qualifiers( Type::Const ), pvt_decl );92 for (int i = 0 ; i < level_of_indirection ; ++i) {93 type = new PointerType( noQualifiers, type );94 }95 return new CastExpr( expr, type );96 }97 98 public:99 VirtualCastCore() :100 indexer(), vcast_decl( nullptr ), pvt_decl( nullptr )101 {}102 103 void premutate( FunctionDecl * functionDecl );104 void premutate( StructDecl * structDecl );105 void premutate( ObjectDecl * objectDecl );106 107 Expression * postmutate( VirtualCastExpr * castExpr );108 109 VirtualTableMap indexer;110 private:111 FunctionDecl *vcast_decl;112 StructDecl *pvt_decl;113 };114 115 void VirtualCastCore::premutate( FunctionDecl * functionDecl ) {116 if ( (! vcast_decl) &&117 functionDecl->get_name() == "__cfavir_virtual_cast" ) {118 vcast_decl = functionDecl;119 }120 }121 122 void VirtualCastCore::premutate( StructDecl * structDecl ) {123 if ( pvt_decl || ! structDecl->has_body() ) {124 return;125 } else if ( structDecl->get_name() == "__cfavir_type_info" ) {126 pvt_decl = structDecl;127 }128 }129 130 void VirtualCastCore::premutate( ObjectDecl * objectDecl ) {131 if ( is_type_id_object( objectDecl ) ) {132 // Multiple definitions should be fine because of linkonce.133 indexer.insert( objectDecl );134 }135 }136 137 /// Better error locations for generated casts.138 CodeLocation castLocation( const VirtualCastExpr * castExpr ) {139 if ( castExpr->location.isSet() ) {140 return castExpr->location;141 } else if ( castExpr->arg->location.isSet() ) {142 return castExpr->arg->location;143 } else if ( castExpr->result->location.isSet() ) {144 return castExpr->result->location;145 } else {146 return CodeLocation();147 }148 }149 150 [[noreturn]] void castError( const VirtualCastExpr * castExpr, std::string const & message ) {151 SemanticError( castLocation( castExpr ), message );152 }153 154 /// Get the base type from a pointer or reference.155 const Type * getBaseType( const Type * type ) {156 if ( auto target = dynamic_cast<const PointerType *>( type ) ) {157 return target->base;158 } else if ( auto target = dynamic_cast<const ReferenceType *>( type ) ) {159 return target->base;160 } else {161 return nullptr;162 }163 }164 165 /* Attempt to follow the "head" field of the structure to get the...166 * Returns nullptr on error, otherwise owner must free returned node.167 */168 StructInstType * followHeadPointerType(169 const StructInstType * oldType,170 const std::string& fieldName,171 const CodeLocation& errorLocation ) {172 173 // First section of the function is all about trying to fill this variable in.174 StructInstType * newType = nullptr;175 {176 const StructDecl * oldDecl = oldType->baseStruct;177 assert( oldDecl );178 179 // Helper function for throwing semantic errors.180 auto throwError = [&fieldName, &errorLocation, &oldDecl](const std::string& message) {181 const std::string& context = "While following head pointer of " +182 oldDecl->name + " named '" + fieldName + "': ";183 SemanticError( errorLocation, context + message );184 };185 186 if ( oldDecl->members.empty() ) {187 throwError( "Type has no fields." );188 }189 const Declaration * memberDecl = oldDecl->members.front();190 assert( memberDecl );191 const ObjectDecl * fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl );192 assert( fieldDecl );193 if ( fieldName != fieldDecl->name ) {194 throwError( "Head field did not have expected name." );195 }196 197 const Type * fieldType = fieldDecl->type;198 if ( nullptr == fieldType ) {199 throwError( "Could not get head field." );200 }201 const PointerType * ptrType = dynamic_cast<const PointerType *>( fieldType );202 if ( nullptr == ptrType ) {203 throwError( "First field is not a pointer type." );204 }205 assert( ptrType->base );206 newType = dynamic_cast<StructInstType *>( ptrType->base );207 if ( nullptr == newType ) {208 throwError( "First field does not point to a structure type." );209 }210 }211 212 // Now we can look into copying it.213 newType = newType->clone();214 if ( ! oldType->parameters.empty() ) {215 deleteAll( newType->parameters );216 newType->parameters.clear();217 cloneAll( oldType->parameters, newType->parameters );218 }219 return newType;220 }221 222 /// Get the type-id type from a virtual type.223 StructInstType * getTypeIdType( const Type * type, const CodeLocation& errorLocation ) {224 const StructInstType * typeInst = dynamic_cast<const StructInstType *>( type );225 if ( nullptr == typeInst ) {226 return nullptr;227 }228 StructInstType * tableInst =229 followHeadPointerType( typeInst, "virtual_table", errorLocation );230 if ( nullptr == tableInst ) {231 return nullptr;232 }233 StructInstType * typeIdInst =234 followHeadPointerType( tableInst, "__cfavir_typeid", errorLocation );235 delete tableInst;236 return typeIdInst;237 }238 239 Expression * VirtualCastCore::postmutate( VirtualCastExpr * castExpr ) {240 assertf( castExpr->result, "Virtual Cast target not found before expansion." );241 242 assert( vcast_decl );243 assert( pvt_decl );244 245 const Type * base_type = getBaseType( castExpr->result );246 if ( nullptr == base_type ) {247 castError( castExpr, "Virtual cast target must be a pointer or reference type." );248 }249 const Type * type_id_type = getTypeIdType( base_type, castLocation( castExpr ) );250 if ( nullptr == type_id_type ) {251 castError( castExpr, "Ill formed virtual cast target type." );252 }253 ObjectDecl * type_id = indexer.lookup( type_id_type );254 delete type_id_type;255 if ( nullptr == type_id ) {256 castError( castExpr, "Virtual cast does not target a virtual type." );257 }258 259 Expression * result = new CastExpr(260 new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), {261 cast_to_type_id( new AddressExpr( new VariableExpr( type_id ) ), 1 ),262 cast_to_type_id( castExpr->get_arg(), 2 ),263 } ),264 castExpr->get_result()->clone()265 );266 267 castExpr->set_arg( nullptr );268 castExpr->set_result( nullptr );269 delete castExpr;270 return result;271 }272 46 273 47 /// Better error locations for generated casts. … … 494 268 } // namespace 495 269 496 void expandCasts( std::list< Declaration * > & translationUnit ) {497 PassVisitor<VirtualCastCore> translator;498 mutateAll( translationUnit, translator );499 }500 501 270 void expandCasts( ast::TranslationUnit & translationUnit ) { 502 271 ast::Pass<ExpandCastsCore>::run( translationUnit ); -
src/Virtual/Tables.cc
r790d835 rc6b4432 21 21 #include "AST/Stmt.hpp" 22 22 #include "AST/Type.hpp" 23 #include <SynTree/Attribute.h>24 #include <SynTree/Declaration.h>25 #include <SynTree/Expression.h>26 #include <SynTree/Statement.h>27 #include <SynTree/Type.h>28 23 29 24 namespace Virtual { … … 65 60 return 17 < name.size() && '_' == name[0] && 66 61 std::string("_vtable_instance") == name.substr(1, name.size() - 17); 67 }68 69 static ObjectDecl * makeVtableDeclaration(70 std::string const & name,71 StructInstType * type, Initializer * init ) {72 Type::StorageClasses storage = noStorageClasses;73 if ( nullptr == init ) {74 storage.is_extern = true;75 }76 return new ObjectDecl(77 name,78 storage,79 LinkageSpec::Cforall,80 nullptr,81 type,82 init83 );84 62 } 85 63 … … 101 79 } 102 80 103 ObjectDecl * makeVtableForward( std::string const & name, StructInstType * type ) {104 assert( type );105 return makeVtableDeclaration( name, type, nullptr );106 }107 108 81 ast::ObjectDecl * makeVtableForward( 109 82 CodeLocation const & location, std::string const & name, … … 111 84 assert( vtableType ); 112 85 return makeVtableDeclaration( location, name, vtableType, nullptr ); 113 }114 115 ObjectDecl * makeVtableInstance(116 std::string const & name, StructInstType * vtableType,117 Type * objectType, Initializer * init ) {118 assert( vtableType );119 assert( objectType );120 StructDecl * vtableStruct = vtableType->baseStruct;121 // Build the initialization122 if ( nullptr == init ) {123 std::list< Initializer * > inits;124 125 // This is going to have to be run before the resolver to connect expressions.126 for ( auto field : vtableStruct->members ) {127 if ( std::string( "parent" ) == field->name ) {128 // This will not work with polymorphic state.129 auto oField = strict_dynamic_cast< ObjectDecl * >( field );130 auto fieldType = strict_dynamic_cast< PointerType * >( oField->type );131 auto parentType = strict_dynamic_cast< StructInstType * >( fieldType->base );132 std::string const & parentInstance = instanceName( parentType->name );133 inits.push_back(134 new SingleInit( new AddressExpr( new NameExpr( parentInstance ) ) ) );135 } else if ( std::string( "__cfavir_typeid" ) == field->name ) {136 std::string const & baseType = baseTypeName( vtableType->name );137 std::string const & typeId = typeIdName( baseType );138 inits.push_back( new SingleInit( new AddressExpr( new NameExpr( typeId ) ) ) );139 } else if ( std::string( "size" ) == field->name ) {140 inits.push_back( new SingleInit( new SizeofExpr( objectType->clone() ) ) );141 } else if ( std::string( "align" ) == field->name ) {142 inits.push_back( new SingleInit( new AlignofExpr( objectType->clone() ) ) );143 } else {144 inits.push_back( new SingleInit( new NameExpr( field->name ) ) );145 }146 }147 init = new ListInit( inits );148 // This should initialize everything except the parent pointer, the149 // size-of and align-of fields. These should be inserted.150 } else {151 assert(false);152 }153 return makeVtableDeclaration( name, vtableType, init );154 86 } 155 87 … … 224 156 } 225 157 226 FunctionDecl * makeGetExceptionForward(227 Type * vtableType, Type * exceptType ) {228 assert( vtableType );229 assert( exceptType );230 FunctionType * type = new FunctionType( noQualifiers, false );231 vtableType->tq.is_const = true;232 type->returnVals.push_back( new ObjectDecl(233 "_retvalue",234 noStorageClasses,235 LinkageSpec::Cforall,236 nullptr,237 new ReferenceType( noQualifiers, vtableType ),238 nullptr,239 { new Attribute("unused") }240 ) );241 type->parameters.push_back( new ObjectDecl(242 "__unused",243 noStorageClasses,244 LinkageSpec::Cforall,245 nullptr,246 new PointerType( noQualifiers, exceptType ),247 nullptr,248 { new Attribute("unused") }249 ) );250 return new FunctionDecl(251 functionName,252 noStorageClasses,253 LinkageSpec::Cforall,254 type,255 nullptr256 );257 }258 259 158 ast::FunctionDecl * makeGetExceptionForward( 260 159 CodeLocation const & location, … … 284 183 } 285 184 286 FunctionDecl * makeGetExceptionFunction(287 ObjectDecl * vtableInstance, Type * exceptType ) {288 assert( vtableInstance );289 assert( exceptType );290 FunctionDecl * func = makeGetExceptionForward(291 vtableInstance->type->clone(), exceptType );292 func->statements = new CompoundStmt( {293 new ReturnStmt( new VariableExpr( vtableInstance ) ),294 } );295 return func;296 }297 298 185 ast::FunctionDecl * makeGetExceptionFunction( 299 186 CodeLocation const & location, … … 307 194 } ); 308 195 return func; 309 }310 311 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType ) {312 assert( typeIdType );313 StructInstType * type = typeIdType->clone();314 type->tq.is_const = true;315 std::string const & typeid_name = typeIdTypeToInstance( typeIdType->name );316 return new ObjectDecl(317 typeid_name,318 noStorageClasses,319 LinkageSpec::Cforall,320 /* bitfieldWidth */ nullptr,321 type,322 new ListInit( { new SingleInit(323 new AddressExpr( new NameExpr( "__cfatid_exception_t" ) )324 ) } ),325 { new Attribute( "cfa_linkonce", {} ) },326 noFuncSpecifiers327 );328 196 } 329 197 -
src/Virtual/Tables.h
r790d835 rc6b4432 18 18 #include <string> 19 19 #include "AST/Fwd.hpp" 20 class Declaration;21 class Expression;22 class FunctionDecl;23 class Initializer;24 class ObjectDecl;25 class StructDecl;26 class StructInstType;27 class Type;28 20 29 21 namespace Virtual { … … 37 29 bool isVTableInstanceName( std::string const & name ); 38 30 39 ObjectDecl * makeVtableForward(40 std::string const & name, StructInstType * vtableType );41 31 /* Create a forward declaration of a vtable of the given type. 42 32 * vtableType node is consumed. … … 46 36 ast::StructInstType const * vtableType ); 47 37 48 ObjectDecl * makeVtableInstance(49 std::string const & name,50 StructInstType * vtableType, Type * objectType,51 Initializer * init = nullptr );52 38 /* Create an initialized definition of a vtable. 53 39 * vtableType and init (if provided) nodes are consumed. … … 61 47 62 48 // Some special code for how exceptions interact with virtual tables. 63 FunctionDecl * makeGetExceptionForward( Type * vtableType, Type * exceptType ); 49 64 50 /* Create a forward declaration of the exception virtual function 65 51 * linking the vtableType to the exceptType. Both nodes are consumed. … … 70 56 ast::Type const * exceptType ); 71 57 72 FunctionDecl * makeGetExceptionFunction(73 ObjectDecl * vtableInstance, Type * exceptType );74 58 /* Create the definition of the exception virtual function. 75 59 * exceptType node is consumed. … … 79 63 ast::ObjectDecl const * vtableInstance, ast::Type const * exceptType ); 80 64 81 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType );82 65 /* Build an instance of the type-id from the type of the type-id. 83 66 * TODO: Should take the parent type. Currently locked to the exception_t.
Note:
See TracChangeset
for help on using the changeset viewer.