source: src/Virtual/ExpandCasts.cc@ 9e27f69

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

I was given a trick with the indexer that fixes some scoping issues with virtual casts.

  • 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 : 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
34 // Indented until the new ast code gets added.
35
36 /// Maps virtual table types the instance for that type.
37 class VirtualTableMap final {
38 ScopedMap<std::string, ObjectDecl *> vtable_instances;
39 public:
40 void enterScope() {
41 vtable_instances.beginScope();
42 }
43 void leaveScope() {
44 vtable_instances.endScope();
45 }
46
47 ObjectDecl * insert( ObjectDecl * vtableDecl ) {
48 std::string const & mangledName = SymTab::Mangler::mangleType( vtableDecl->type );
49 ObjectDecl *& value = vtable_instances[ mangledName ];
50 if ( value ) {
51 if ( vtableDecl->storageClasses.is_extern ) {
52 return nullptr;
53 } else if ( ! value->storageClasses.is_extern ) {
54 return value;
55 }
56 }
57 value = vtableDecl;
58 return nullptr;
59 }
60
61 ObjectDecl * lookup( const Type * vtableType ) {
62 std::string const & mangledName = SymTab::Mangler::mangleType( vtableType );
63 const auto it = vtable_instances.find( mangledName );
64 return ( vtable_instances.end() == it ) ? nullptr : it->second;
65 }
66 };
67
68 /* Currently virtual depends on the rather brittle name matching between
69 * a (strict/explicate) virtual type, its vtable type and the vtable
70 * instance.
71 * A stronger implementation, would probably keep track of those triads
72 * 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 } // namespace
99
100 class VirtualCastCore {
101 Type * pointer_to_pvt(int level_of_indirection) {
102 Type * type = new StructInstType(
103 Type::Qualifiers( Type::Const ), pvt_decl );
104 for (int i = 0 ; i < level_of_indirection ; ++i) {
105 type = new PointerType( noQualifiers, type );
106 }
107 return type;
108 }
109
110 public:
111 VirtualCastCore() :
112 indexer(), vcast_decl( nullptr ), pvt_decl( nullptr )
113 {}
114
115 void premutate( FunctionDecl * functionDecl );
116 void premutate( StructDecl * structDecl );
117 void premutate( ObjectDecl * objectDecl );
118
119 Expression * postmutate( VirtualCastExpr * castExpr );
120
121 VirtualTableMap indexer;
122 private:
123 FunctionDecl *vcast_decl;
124 StructDecl *pvt_decl;
125 };
126
127 void VirtualCastCore::premutate( FunctionDecl * functionDecl ) {
128 if ( (! vcast_decl) &&
129 functionDecl->get_name() == "__cfa__virtual_cast" ) {
130 vcast_decl = functionDecl;
131 }
132 }
133
134 void VirtualCastCore::premutate( StructDecl * structDecl ) {
135 if ( pvt_decl || ! structDecl->has_body() ) {
136 return;
137 } else if ( structDecl->get_name() == "__cfa__parent_vtable" ) {
138 pvt_decl = structDecl;
139 }
140 }
141
142 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 }
150 }
151 }
152
153 namespace {
154
155 /// Better error locations for generated casts.
156 CodeLocation castLocation( const VirtualCastExpr * castExpr ) {
157 if ( castExpr->location.isSet() ) {
158 return castExpr->location;
159 } else if ( castExpr->arg->location.isSet() ) {
160 return castExpr->arg->location;
161 } else if ( castExpr->result->location.isSet() ) {
162 return castExpr->result->location;
163 } else {
164 return CodeLocation();
165 }
166 }
167
168 [[noreturn]] void castError( const VirtualCastExpr * castExpr, std::string const & message ) {
169 SemanticError( castLocation( castExpr ), message );
170 }
171
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;
179 } 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();
194 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;
220 }
221
222 } // namespace
223
224 Expression * VirtualCastCore::postmutate( VirtualCastExpr * castExpr ) {
225 assertf( castExpr->result, "Virtual Cast target not found before expansion." );
226
227 assert( vcast_decl );
228 assert( pvt_decl );
229
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." );
235 }
236
237 Expression * result = new CastExpr(
238 new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), {
239 new CastExpr(
240 new AddressExpr( new VariableExpr( table ) ),
241 pointer_to_pvt(1)
242 ),
243 new CastExpr(
244 castExpr->get_arg(),
245 pointer_to_pvt(2)
246 )
247 } ),
248 castExpr->get_result()->clone()
249 );
250
251 castExpr->set_arg( nullptr );
252 castExpr->set_result( nullptr );
253 delete castExpr;
254 delete vtable_type;
255 return result;
256 }
257
258 void expandCasts( std::list< Declaration * > & translationUnit ) {
259 PassVisitor<VirtualCastCore> translator;
260 mutateAll( translationUnit, translator );
261 }
262}
Note: See TracBrowser for help on using the repository browser.