Changes in src/Virtual/ExpandCasts.cc [c36814a:8f910430]
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Virtual/ExpandCasts.cc
rc36814a r8f910430 10 10 // Created On : Mon Jul 24 13:59:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Thu Aug 11 12:06:00 202213 // Update Count : 512 // Last Modified On : Fri Jul 31 10:29:00 2020 13 // Update Count : 4 14 14 // 15 15 … … 20 20 #include <string> // for string, allocator, operator==, ope... 21 21 22 #include "AST/Decl.hpp"23 #include "AST/Expr.hpp"24 #include "AST/Pass.hpp"25 22 #include "Common/PassVisitor.h" // for PassVisitor 26 23 #include "Common/ScopedMap.h" // for ScopedMap … … 35 32 namespace Virtual { 36 33 37 namespace { 38 39 bool is_prefix( const std::string & prefix, const std::string& entire ) { 34 static bool is_prefix( const std::string & prefix, const std::string& entire ) { 40 35 size_t const p_size = prefix.size(); 41 36 return (p_size < entire.size() && prefix == entire.substr(0, p_size)); 42 37 } 43 38 44 bool is_type_id_object( const ObjectDecl * objectDecl ) {39 static bool is_type_id_object( const ObjectDecl * objectDecl ) { 45 40 const std::string & objectName = objectDecl->name; 46 41 return is_prefix( "__cfatid_", objectName ); 47 }48 49 bool is_type_id_object( const ast::ObjectDecl * decl ) {50 return is_prefix( "__cfatid_", decl->name );51 42 } 52 43 … … 133 124 } 134 125 } 126 127 namespace { 135 128 136 129 /// Better error locations for generated casts. … … 236 229 } 237 230 231 } // namespace 232 238 233 Expression * VirtualCastCore::postmutate( VirtualCastExpr * castExpr ) { 239 234 assertf( castExpr->result, "Virtual Cast target not found before expansion." ); … … 270 265 } 271 266 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 ); 281 270 } 282 271 } 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 pointed380 /// 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 as461 // 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 } // namespace496 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.