source: src/Virtual/ExpandCasts.cc@ 86b8d16

ADT ast-experimental pthread-emulation qualifiedEnum
Last change on this file since 86b8d16 was 8f910430, checked in by Andrew Beach <ajbeach@…>, 4 years ago

Updated the virtual module to prefix the names with the new convention and change the parent_vtable into type_info.

  • Property mode set to 100644
File size: 8.5 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// ExpandCasts.cc --
8//
9// Author : Andrew Beach
10// Created On : Mon Jul 24 13:59:00 2017
11// Last Modified By : Andrew Beach
12// Last Modified On : Fri Jul 31 10:29:00 2020
13// Update Count : 4
14//
15
16#include "ExpandCasts.h"
17
18#include <cassert> // for assert, assertf
19#include <iterator> // for back_inserter, inserter
20#include <string> // for string, allocator, operator==, ope...
21
22#include "Common/PassVisitor.h" // for PassVisitor
23#include "Common/ScopedMap.h" // for ScopedMap
24#include "Common/SemanticError.h" // for SemanticError
25#include "SymTab/Mangler.h" // for mangleType
26#include "SynTree/Declaration.h" // for ObjectDecl, StructDecl, FunctionDecl
27#include "SynTree/Expression.h" // for VirtualCastExpr, CastExpr, Address...
28#include "SynTree/Mutator.h" // for mutateAll
29#include "SynTree/Type.h" // for Type, PointerType, StructInstType
30#include "SynTree/Visitor.h" // for acceptAll
31
32namespace Virtual {
33
34static 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
39static bool is_type_id_object( const ObjectDecl * objectDecl ) {
40 const std::string & objectName = objectDecl->name;
41 return is_prefix( "__cfatid_", objectName );
42}
43
44 // Indented until the new ast code gets added.
45
46 /// Maps virtual table types the instance for that type.
47 class VirtualTableMap final {
48 ScopedMap<std::string, ObjectDecl *> vtable_instances;
49 public:
50 void enterScope() {
51 vtable_instances.beginScope();
52 }
53 void leaveScope() {
54 vtable_instances.endScope();
55 }
56
57 ObjectDecl * insert( ObjectDecl * vtableDecl ) {
58 std::string const & mangledName = SymTab::Mangler::mangleType( vtableDecl->type );
59 ObjectDecl *& value = vtable_instances[ mangledName ];
60 if ( value ) {
61 if ( vtableDecl->storageClasses.is_extern ) {
62 return nullptr;
63 } else if ( ! value->storageClasses.is_extern ) {
64 return value;
65 }
66 }
67 value = vtableDecl;
68 return nullptr;
69 }
70
71 ObjectDecl * lookup( const Type * vtableType ) {
72 std::string const & mangledName = SymTab::Mangler::mangleType( vtableType );
73 const auto it = vtable_instances.find( mangledName );
74 return ( vtable_instances.end() == it ) ? nullptr : it->second;
75 }
76 };
77
78 class VirtualCastCore {
79 CastExpr * cast_to_type_id( Expression * expr, int level_of_indirection ) {
80 Type * type = new StructInstType(
81 Type::Qualifiers( Type::Const ), pvt_decl );
82 for (int i = 0 ; i < level_of_indirection ; ++i) {
83 type = new PointerType( noQualifiers, type );
84 }
85 return new CastExpr( expr, type );
86 }
87
88 public:
89 VirtualCastCore() :
90 indexer(), vcast_decl( nullptr ), pvt_decl( nullptr )
91 {}
92
93 void premutate( FunctionDecl * functionDecl );
94 void premutate( StructDecl * structDecl );
95 void premutate( ObjectDecl * objectDecl );
96
97 Expression * postmutate( VirtualCastExpr * castExpr );
98
99 VirtualTableMap indexer;
100 private:
101 FunctionDecl *vcast_decl;
102 StructDecl *pvt_decl;
103 };
104
105 void VirtualCastCore::premutate( FunctionDecl * functionDecl ) {
106 if ( (! vcast_decl) &&
107 functionDecl->get_name() == "__cfavir_virtual_cast" ) {
108 vcast_decl = functionDecl;
109 }
110 }
111
112 void VirtualCastCore::premutate( StructDecl * structDecl ) {
113 if ( pvt_decl || ! structDecl->has_body() ) {
114 return;
115 } else if ( structDecl->get_name() == "__cfavir_type_info" ) {
116 pvt_decl = structDecl;
117 }
118 }
119
120 void VirtualCastCore::premutate( ObjectDecl * objectDecl ) {
121 if ( is_type_id_object( objectDecl ) ) {
122 // Multiple definitions should be fine because of linkonce.
123 indexer.insert( objectDecl );
124 }
125 }
126
127 namespace {
128
129 /// Better error locations for generated casts.
130 CodeLocation castLocation( const VirtualCastExpr * castExpr ) {
131 if ( castExpr->location.isSet() ) {
132 return castExpr->location;
133 } else if ( castExpr->arg->location.isSet() ) {
134 return castExpr->arg->location;
135 } else if ( castExpr->result->location.isSet() ) {
136 return castExpr->result->location;
137 } else {
138 return CodeLocation();
139 }
140 }
141
142 [[noreturn]] void castError( const VirtualCastExpr * castExpr, std::string const & message ) {
143 SemanticError( castLocation( castExpr ), message );
144 }
145
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;
152 } else {
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();
182 assert( memberDecl );
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;
229 }
230
231 } // namespace
232
233 Expression * VirtualCastCore::postmutate( VirtualCastExpr * castExpr ) {
234 assertf( castExpr->result, "Virtual Cast target not found before expansion." );
235
236 assert( vcast_decl );
237 assert( pvt_decl );
238
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." );
251 }
252
253 Expression * result = new CastExpr(
254 new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), {
255 cast_to_type_id( new AddressExpr( new VariableExpr( type_id ) ), 1 ),
256 cast_to_type_id( castExpr->get_arg(), 2 ),
257 } ),
258 castExpr->get_result()->clone()
259 );
260
261 castExpr->set_arg( nullptr );
262 castExpr->set_result( nullptr );
263 delete castExpr;
264 return result;
265 }
266
267 void expandCasts( std::list< Declaration * > & translationUnit ) {
268 PassVisitor<VirtualCastCore> translator;
269 mutateAll( translationUnit, translator );
270 }
271}
Note: See TracBrowser for help on using the repository browser.