source: src/Virtual/ExpandCasts.cc @ f19fbbc

arm-ehjacob/cs343-translationnew-astnew-ast-unique-expr
Last change on this file since f19fbbc was f19fbbc, checked in by Andrew Beach <ajbeach@…>, 15 months 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.