source: src/Virtual/ExpandCasts.cc @ 912cc7d7

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since 912cc7d7 was 6dba8755, checked in by Andrew Beach <ajbeach@…>, 4 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.