Changes in src/Virtual/ExpandCasts.cc [ccbc65c:8f910430]
- File:
-
- 1 edited
-
src/Virtual/ExpandCasts.cc (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/Virtual/ExpandCasts.cc
rccbc65c 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 {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 pointed379 /// 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 as460 // 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 } // namespace495 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.