source: src/Virtual/ExpandCasts.cc @ c4f8170

ADTast-experimentalenumforall-pointer-decaypthread-emulationqualifiedEnum
Last change on this file since c4f8170 was 8f910430, checked in by Andrew Beach <ajbeach@…>, 3 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.