Changeset ecfd758 for src/Virtual/ExpandCasts.cc
- Timestamp:
- Apr 9, 2021, 2:11:43 PM (4 years ago)
- Branches:
- ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- b91bfde
- Parents:
- e07b589
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Virtual/ExpandCasts.cc
re07b589 recfd758 32 32 namespace Virtual { 33 33 34 static bool is_prefix( const std::string & prefix, const std::string& entire ) { 35 size_t const p_size = prefix.size(); 36 return (p_size < entire.size() && prefix == entire.substr(0, p_size)); 37 } 38 39 static bool is_type_id_object( const ObjectDecl * objectDecl ) { 40 const std::string & objectName = objectDecl->name; 41 return is_prefix( "__cfatid_", objectName ); 42 } 43 34 44 // Indented until the new ast code gets added. 35 45 … … 66 76 }; 67 77 68 /* Currently virtual depends on the rather brittle name matching between69 * a (strict/explicate) virtual type, its vtable type and the vtable70 * instance.71 * A stronger implementation, would probably keep track of those triads72 * and use that information to create better error messages.73 */74 75 namespace {76 77 std::string get_vtable_name( std::string const & name ) {78 return name + "_vtable";79 }80 81 std::string get_vtable_inst_name( std::string const & name ) {82 return std::string("_") + get_vtable_name( name ) + "_instance";83 }84 85 std::string get_vtable_name_root( std::string const & name ) {86 return name.substr(0, name.size() - 7 );87 }88 89 std::string get_vtable_inst_name_root( std::string const & name ) {90 return get_vtable_name_root( name.substr(1, name.size() - 10 ) );91 }92 93 bool is_vtable_inst_name( std::string const & name ) {94 return 17 < name.size() &&95 name == get_vtable_inst_name( get_vtable_inst_name_root( name ) );96 }97 98 } // namespace99 100 78 class VirtualCastCore { 101 79 Type * pointer_to_pvt(int level_of_indirection) { … … 141 119 142 120 void VirtualCastCore::premutate( ObjectDecl * objectDecl ) { 143 if ( is_vtable_inst_name( objectDecl->get_name() ) ) { 144 if ( ObjectDecl * existing = indexer.insert( objectDecl ) ) { 145 std::string msg = "Repeated instance of virtual table, original found at: "; 146 msg += existing->location.filename; 147 msg += ":" + toString( existing->location.first_line ); 148 SemanticError( objectDecl->location, msg ); 149 } 121 if ( is_type_id_object( objectDecl ) ) { 122 // Multiple definitions should be fine because of linkonce. 123 indexer.insert( objectDecl ); 150 124 } 151 125 } … … 170 144 } 171 145 172 /// Get the virtual table type used in a virtual cast. 173 Type * getVirtualTableType( const VirtualCastExpr * castExpr ) { 174 const Type * objectType; 175 if ( auto target = dynamic_cast<const PointerType *>( castExpr->result ) ) { 176 objectType = target->base; 177 } else if ( auto target = dynamic_cast<const ReferenceType *>( castExpr->result ) ) { 178 objectType = target->base; 146 /// Get the base type from a pointer or reference. 147 const Type * getBaseType( const Type * type ) { 148 if ( auto target = dynamic_cast<const PointerType *>( type ) ) { 149 return target->base; 150 } else if ( auto target = dynamic_cast<const ReferenceType *>( type ) ) { 151 return target->base; 179 152 } else { 180 castError( castExpr, "Virtual cast type must be a pointer or reference type." ); 181 } 182 assert( objectType ); 183 184 const StructInstType * structType = dynamic_cast<const StructInstType *>( objectType ); 185 if ( nullptr == structType ) { 186 castError( castExpr, "Virtual cast type must refer to a structure type." ); 187 } 188 const StructDecl * structDecl = structType->baseStruct; 189 assert( structDecl ); 190 191 const ObjectDecl * fieldDecl = nullptr; 192 if ( 0 < structDecl->members.size() ) { 193 const Declaration * memberDecl = structDecl->members.front(); 153 return nullptr; 154 } 155 } 156 157 /* Attempt to follow the "head" field of the structure to get the... 158 * Returns nullptr on error, otherwise owner must free returned node. 159 */ 160 StructInstType * followHeadPointerType( 161 const StructInstType * oldType, 162 const std::string& fieldName, 163 const CodeLocation& errorLocation ) { 164 165 // First section of the function is all about trying to fill this variable in. 166 StructInstType * newType = nullptr; 167 { 168 const StructDecl * oldDecl = oldType->baseStruct; 169 assert( oldDecl ); 170 171 // Helper function for throwing semantic errors. 172 auto throwError = [&fieldName, &errorLocation, &oldDecl](const std::string& message) { 173 const std::string& context = "While following head pointer of " + 174 oldDecl->name + " named '" + fieldName + "': "; 175 SemanticError( errorLocation, context + message ); 176 }; 177 178 if ( oldDecl->members.empty() ) { 179 throwError( "Type has no fields." ); 180 } 181 const Declaration * memberDecl = oldDecl->members.front(); 194 182 assert( memberDecl ); 195 fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl ); 196 if ( fieldDecl && fieldDecl->name != "virtual_table" ) { 197 fieldDecl = nullptr; 198 } 199 } 200 if ( nullptr == fieldDecl ) { 201 castError( castExpr, "Virtual cast type must have a leading virtual_table field." ); 202 } 203 const PointerType * fieldType = dynamic_cast<const PointerType *>( fieldDecl->type ); 204 if ( nullptr == fieldType ) { 205 castError( castExpr, "Virtual cast type virtual_table field is not a pointer." ); 206 } 207 assert( fieldType->base ); 208 auto virtualStructType = dynamic_cast<const StructInstType *>( fieldType->base ); 209 assert( virtualStructType ); 210 211 // Here is the type, but if it is polymorphic it will have lost information. 212 // (Always a clone so that it may always be deleted.) 213 StructInstType * virtualType = virtualStructType->clone(); 214 if ( ! structType->parameters.empty() ) { 215 deleteAll( virtualType->parameters ); 216 virtualType->parameters.clear(); 217 cloneAll( structType->parameters, virtualType->parameters ); 218 } 219 return virtualType; 183 const ObjectDecl * fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl ); 184 assert( fieldDecl ); 185 if ( fieldName != fieldDecl->name ) { 186 throwError( "Head field did not have expected name." ); 187 } 188 189 const Type * fieldType = fieldDecl->type; 190 if ( nullptr == fieldType ) { 191 throwError( "Could not get head field." ); 192 } 193 const PointerType * ptrType = dynamic_cast<const PointerType *>( fieldType ); 194 if ( nullptr == ptrType ) { 195 throwError( "First field is not a pointer type." ); 196 } 197 assert( ptrType->base ); 198 newType = dynamic_cast<StructInstType *>( ptrType->base ); 199 if ( nullptr == newType ) { 200 throwError( "First field does not point to a structure type." ); 201 } 202 } 203 204 // Now we can look into copying it. 205 newType = newType->clone(); 206 if ( ! oldType->parameters.empty() ) { 207 deleteAll( newType->parameters ); 208 newType->parameters.clear(); 209 cloneAll( oldType->parameters, newType->parameters ); 210 } 211 return newType; 212 } 213 214 /// Get the type-id type from a virtual type. 215 StructInstType * getTypeIdType( const Type * type, const CodeLocation& errorLocation ) { 216 const StructInstType * typeInst = dynamic_cast<const StructInstType *>( type ); 217 if ( nullptr == typeInst ) { 218 return nullptr; 219 } 220 StructInstType * tableInst = 221 followHeadPointerType( typeInst, "virtual_table", errorLocation ); 222 if ( nullptr == tableInst ) { 223 return nullptr; 224 } 225 StructInstType * typeIdInst = 226 followHeadPointerType( tableInst, "__cfavir_typeid", errorLocation ); 227 delete tableInst; 228 return typeIdInst; 220 229 } 221 230 … … 228 237 assert( pvt_decl ); 229 238 230 const Type * vtable_type = getVirtualTableType( castExpr ); 231 ObjectDecl * table = indexer.lookup( vtable_type ); 232 if ( nullptr == table ) { 233 SemanticError( castLocation( castExpr ), 234 "Could not find virtual table instance." ); 239 const Type * base_type = getBaseType( castExpr->result ); 240 if ( nullptr == base_type ) { 241 castError( castExpr, "Virtual cast target must be a pointer or reference type." ); 242 } 243 const Type * type_id_type = getTypeIdType( base_type, castLocation( castExpr ) ); 244 if ( nullptr == type_id_type ) { 245 castError( castExpr, "Ill formed virtual cast target type." ); 246 } 247 ObjectDecl * type_id = indexer.lookup( type_id_type ); 248 delete type_id_type; 249 if ( nullptr == type_id ) { 250 castError( castExpr, "Virtual cast does not target a virtual type." ); 235 251 } 236 252 … … 238 254 new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), { 239 255 new CastExpr( 240 new AddressExpr( new VariableExpr( t able) ),256 new AddressExpr( new VariableExpr( type_id ) ), 241 257 pointer_to_pvt(1) 242 258 ), … … 252 268 castExpr->set_result( nullptr ); 253 269 delete castExpr; 254 delete vtable_type;255 270 return result; 256 271 }
Note: See TracChangeset
for help on using the changeset viewer.