source: src/Virtual/ExpandCasts.cc@ 4cf617e

ADT arm-eh ast-experimental enum forall-pointer-decay jacob/cs343-translation new-ast new-ast-unique-expr pthread-emulation qualifiedEnum
Last change on this file since 4cf617e was f19fbbc, checked in by Andrew Beach <ajbeach@…>, 5 years ago

Fixed the virtual system so it can handle in polymorphic virtual tables at least as well as the resolver does.

  • Property mode set to 100644
File size: 8.2 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 : Tue Jul 22 10:04:00 2020
13// Update Count : 3
14//
15
16#include "ExpandCasts.h"
17
18#include <cassert> // for assert, assertf
19#include <iterator> // for back_inserter, inserter
20#include <map> // for map, _Rb_tree_iterator, map<>::ite...
21#include <string> // for string, allocator, operator==, ope...
22#include <utility> // for pair
23
24#include "Common/PassVisitor.h" // for PassVisitor
25#include "Common/SemanticError.h" // for SemanticError
26#include "SymTab/Mangler.h" // for mangleType
27#include "SynTree/Declaration.h" // for ObjectDecl, StructDecl, FunctionDecl
28#include "SynTree/Expression.h" // for VirtualCastExpr, CastExpr, Address...
29#include "SynTree/Mutator.h" // for mutateAll
30#include "SynTree/Type.h" // for Type, PointerType, StructInstType
31#include "SynTree/Visitor.h" // for acceptAll
32
33namespace Virtual {
34
35 // Indented until the new ast code gets added.
36
37 /// Maps virtual table types the instance for that type.
38 class VirtualTableMap final {
39 std::unordered_map<std::string, ObjectDecl *> vtable_instances;
40 public:
41 ObjectDecl * insert( ObjectDecl * vtableDecl ) {
42 std::string const & mangledName = SymTab::Mangler::mangleType( vtableDecl->type );
43 ObjectDecl *& value = vtable_instances[ mangledName ];
44 if ( value ) {
45 if ( vtableDecl->storageClasses.is_extern ) {
46 return nullptr;
47 } else if ( ! value->storageClasses.is_extern ) {
48 return value;
49 }
50 }
51 value = vtableDecl;
52 return nullptr;
53 }
54
55 ObjectDecl * lookup( const Type * vtableType ) {
56 std::string const & mangledName = SymTab::Mangler::mangleType( vtableType );
57 const auto it = vtable_instances.find( mangledName );
58 return ( vtable_instances.end() == it ) ? nullptr : it->second;
59 }
60 };
61
62 /* Currently virtual depends on the rather brittle name matching between
63 * a (strict/explicate) virtual type, its vtable type and the vtable
64 * instance.
65 * A stronger implementation, would probably keep track of those triads
66 * and use that information to create better error messages.
67 */
68
69 namespace {
70
71 std::string get_vtable_name( std::string const & name ) {
72 return name + "_vtable";
73 }
74
75 std::string get_vtable_inst_name( std::string const & name ) {
76 return std::string("_") + get_vtable_name( name ) + "_instance";
77 }
78
79 std::string get_vtable_name_root( std::string const & name ) {
80 return name.substr(0, name.size() - 7 );
81 }
82
83 std::string get_vtable_inst_name_root( std::string const & name ) {
84 return get_vtable_name_root( name.substr(1, name.size() - 10 ) );
85 }
86
87 bool is_vtable_inst_name( std::string const & name ) {
88 return 17 < name.size() &&
89 name == get_vtable_inst_name( get_vtable_inst_name_root( name ) );
90 }
91
92 } // namespace
93
94 class VirtualCastCore {
95 VirtualTableMap vtable_instances;
96 FunctionDecl *vcast_decl;
97 StructDecl *pvt_decl;
98
99 Type * pointer_to_pvt(int level_of_indirection) {
100 Type * type = new StructInstType(
101 Type::Qualifiers( Type::Const ), pvt_decl );
102 for (int i = 0 ; i < level_of_indirection ; ++i) {
103 type = new PointerType( noQualifiers, type );
104 }
105 return type;
106 }
107
108 public:
109 VirtualCastCore() :
110 vtable_instances(), vcast_decl( nullptr ), pvt_decl( nullptr )
111 {}
112
113 void premutate( FunctionDecl * functionDecl );
114 void premutate( StructDecl * structDecl );
115 void premutate( ObjectDecl * objectDecl );
116
117 Expression * postmutate( VirtualCastExpr * castExpr );
118 };
119
120 void VirtualCastCore::premutate( FunctionDecl * functionDecl ) {
121 if ( (! vcast_decl) &&
122 functionDecl->get_name() == "__cfa__virtual_cast" ) {
123 vcast_decl = functionDecl;
124 }
125 }
126
127 void VirtualCastCore::premutate( StructDecl * structDecl ) {
128 if ( pvt_decl || ! structDecl->has_body() ) {
129 return;
130 } else if ( structDecl->get_name() == "__cfa__parent_vtable" ) {
131 pvt_decl = structDecl;
132 }
133 }
134
135 void VirtualCastCore::premutate( ObjectDecl * objectDecl ) {
136 if ( is_vtable_inst_name( objectDecl->get_name() ) ) {
137 if ( ObjectDecl * existing = vtable_instances.insert( objectDecl ) ) {
138 std::string msg = "Repeated instance of virtual table, original found at: ";
139 msg += existing->location.filename;
140 msg += ":" + toString( existing->location.first_line );
141 SemanticError( objectDecl->location, msg );
142 }
143 }
144 }
145
146 namespace {
147
148 /// Better error locations for generated casts.
149 CodeLocation castLocation( const VirtualCastExpr * castExpr ) {
150 if ( castExpr->location.isSet() ) {
151 return castExpr->location;
152 } else if ( castExpr->arg->location.isSet() ) {
153 return castExpr->arg->location;
154 } else if ( castExpr->result->location.isSet() ) {
155 return castExpr->result->location;
156 } else {
157 return CodeLocation();
158 }
159 }
160
161 [[noreturn]] void castError( const VirtualCastExpr * castExpr, std::string const & message ) {
162 SemanticError( castLocation( castExpr ), message );
163 }
164
165 /// Get the virtual table type used in a virtual cast.
166 Type * getVirtualTableType( const VirtualCastExpr * castExpr ) {
167 const Type * objectType;
168 if ( auto target = dynamic_cast<const PointerType *>( castExpr->result ) ) {
169 objectType = target->base;
170 } else if ( auto target = dynamic_cast<const ReferenceType *>( castExpr->result ) ) {
171 objectType = target->base;
172 } else {
173 castError( castExpr, "Virtual cast type must be a pointer or reference type." );
174 }
175 assert( objectType );
176
177 const StructInstType * structType = dynamic_cast<const StructInstType *>( objectType );
178 if ( nullptr == structType ) {
179 castError( castExpr, "Virtual cast type must refer to a structure type." );
180 }
181 const StructDecl * structDecl = structType->baseStruct;
182 assert( structDecl );
183
184 const ObjectDecl * fieldDecl = nullptr;
185 if ( 0 < structDecl->members.size() ) {
186 const Declaration * memberDecl = structDecl->members.front();
187 assert( memberDecl );
188 fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl );
189 if ( fieldDecl && fieldDecl->name != "virtual_table" ) {
190 fieldDecl = nullptr;
191 }
192 }
193 if ( nullptr == fieldDecl ) {
194 castError( castExpr, "Virtual cast type must have a leading virtual_table field." );
195 }
196 const PointerType * fieldType = dynamic_cast<const PointerType *>( fieldDecl->type );
197 if ( nullptr == fieldType ) {
198 castError( castExpr, "Virtual cast type virtual_table field is not a pointer." );
199 }
200 assert( fieldType->base );
201 auto virtualStructType = dynamic_cast<const StructInstType *>( fieldType->base );
202 assert( virtualStructType );
203
204 // Here is the type, but if it is polymorphic it will have lost information.
205 // (Always a clone so that it may always be deleted.)
206 StructInstType * virtualType = virtualStructType->clone();
207 if ( ! structType->parameters.empty() ) {
208 deleteAll( virtualType->parameters );
209 virtualType->parameters.clear();
210 cloneAll( structType->parameters, virtualType->parameters );
211 }
212 return virtualType;
213 }
214
215 } // namespace
216
217 Expression * VirtualCastCore::postmutate( VirtualCastExpr * castExpr ) {
218 assertf( castExpr->result, "Virtual Cast target not found before expansion." );
219
220 assert( vcast_decl );
221 assert( pvt_decl );
222
223 const Type * vtable_type = getVirtualTableType( castExpr );
224 ObjectDecl * table = vtable_instances.lookup( vtable_type );
225 if ( nullptr == table ) {
226 SemanticError( castLocation( castExpr ),
227 "Could not find virtual table instance." );
228 }
229
230 Expression * result = new CastExpr(
231 new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), {
232 new CastExpr(
233 new AddressExpr( new VariableExpr( table ) ),
234 pointer_to_pvt(1)
235 ),
236 new CastExpr(
237 castExpr->get_arg(),
238 pointer_to_pvt(2)
239 )
240 } ),
241 castExpr->get_result()->clone()
242 );
243
244 castExpr->set_arg( nullptr );
245 castExpr->set_result( nullptr );
246 delete castExpr;
247 delete vtable_type;
248 return result;
249 }
250
251 void expandCasts( std::list< Declaration * > & translationUnit ) {
252 PassVisitor<VirtualCastCore> translator;
253 mutateAll( translationUnit, translator );
254 }
255}
Note: See TracBrowser for help on using the repository browser.