source: src/Validate/ReplaceTypedef.cpp @ 60f4919

Last change on this file since 60f4919 was 251ce80, checked in by Fangren Yu <f37yu@…>, 18 months ago

remove reference to symbol table in unify

  • Property mode set to 100644
File size: 12.3 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2018 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// ReplaceTypedef.cpp -- Fill in all typedefs with the underlying type.
8//
9// Author           : Andrew Beach
10// Created On       : Tue Jun 29 14:59:00 2022
11// Last Modified By : Andrew Beach
12// Last Modified On : Tue Sep 20 17:00:00 2022
13// Update Count     : 2
14//
15
16#include "ReplaceTypedef.hpp"
17
18#include "AST/Copy.hpp"
19#include "AST/Pass.hpp"
20#include "Common/ScopedMap.h"
21#include "Common/UniqueName.h"
22#include "Common/utility.h"
23#include "ResolvExpr/Unify.h"
24
25namespace Validate {
26
27namespace {
28
29bool isNonParameterAttribute( ast::Attribute const * attr ) {
30        static const std::vector<std::string> bad_names = {
31                "aligned", "__aligned__",
32        };
33        for ( auto name : bad_names ) {
34                if ( name == attr->name ) {
35                        return true;
36                }
37        }
38        return false;
39}
40
41struct ReplaceTypedefCore final :
42                public ast::WithCodeLocation,
43                public ast::WithDeclsToAdd<>,
44                public ast::WithGuards,
45                public ast::WithShortCircuiting,
46                public ast::WithVisitorRef<ReplaceTypedefCore> {
47
48        void previsit( ast::QualifiedType const * );
49        ast::Type const * postvisit( ast::QualifiedType const * );
50        ast::Type const * postvisit( ast::TypeInstType const * );
51        ast::Decl const * postvisit( ast::TypedefDecl const * );
52        void previsit( ast::TypeDecl const * );
53        void previsit( ast::FunctionDecl const * );
54        void previsit( ast::ObjectDecl const * );
55        ast::DeclWithType const * postvisit( ast::ObjectDecl const * );
56
57        void previsit( ast::CastExpr const * );
58        void previsit( ast::CompoundStmt const * );
59        void postvisit( ast::CompoundStmt const * );
60
61        ast::StructDecl const * previsit( ast::StructDecl const * );
62        ast::UnionDecl const * previsit( ast::UnionDecl const * );
63        void previsit( ast::EnumDecl const * );
64        void previsit( ast::TraitDecl const * );
65
66        template<typename AggrDecl>
67        void addImplicitTypedef( AggrDecl * aggDecl );
68        template<typename AggrDecl>
69        AggrDecl const * handleAggregate( AggrDecl const * aggDecl );
70
71        using TypedefDeclPtr = ast::ptr<ast::TypedefDecl>;
72        using TypedefMap = ScopedMap<std::string, std::pair<TypedefDeclPtr, int>>;
73        using TypeDeclMap = ScopedMap<std::string, ast::TypeDecl const *>;
74
75        TypedefMap typedefNames;
76        TypeDeclMap typedeclNames;
77        int scopeLevel;
78        bool isAtFunctionTop = false;
79};
80
81void ReplaceTypedefCore::previsit( ast::QualifiedType const * ) {
82        visit_children = false;
83}
84
85ast::Type const * ReplaceTypedefCore::postvisit(
86                ast::QualifiedType const * type ) {
87        // Replacing typedefs only makes sense for the 'oldest ancestor'
88        // of the qualified type.
89        return ast::mutate_field( type, &ast::QualifiedType::parent,
90                type->parent->accept( *visitor ) );
91}
92
93ast::Type const * ReplaceTypedefCore::postvisit(
94                ast::TypeInstType const * type ) {
95        // Instances of typedef types will come here. If it is an instance
96        // of a typedef type, link the instance to its actual type.
97        TypedefMap::const_iterator def = typedefNames.find( type->name );
98        if ( def != typedefNames.end() ) {
99                ast::Type * ret = ast::deepCopy( def->second.first->base );
100                ret->qualifiers |= type->qualifiers;
101                // We ignore certain attributes on function parameters if they arrive
102                // by typedef. GCC appears to do the same thing.
103                if ( isAtFunctionTop ) {
104                        erase_if( ret->attributes, isNonParameterAttribute );
105                }
106                for ( const auto & attribute : type->attributes ) {
107                        ret->attributes.push_back( attribute );
108                }
109                // Place instance parameters on the typedef'd type.
110                if ( !type->params.empty() ) {
111                        auto rtt = dynamic_cast<ast::BaseInstType *>( ret );
112                        if ( !rtt ) {
113                                assert( location );
114                                SemanticError( *location, "Cannot apply type parameters to base type of " + type->name );
115                        }
116                        rtt->params.clear();
117                        for ( auto it : type->params ) {
118                                rtt->params.push_back( ast::deepCopy( it ) );
119                        }
120                        // Recursively fix typedefs on parameters.
121                        ast::mutate_each( rtt, &ast::BaseInstType::params, *visitor );
122                }
123                return ret;
124        } else {
125                TypeDeclMap::const_iterator base = typedeclNames.find( type->name );
126                if ( base == typedeclNames.end() ) {
127                        assert( location );
128                        SemanticError( *location, toString( "Use of undefined type ", type->name ) );
129                }
130                return ast::mutate_field( type, &ast::TypeInstType::base, base->second );
131        }
132}
133
134struct VarLenChecker : public ast::WithShortCircuiting {
135        bool result = false;
136        void previsit( ast::FunctionType const * ) { visit_children = false; }
137        void previsit( ast::ArrayType const * at ) { result |= at->isVarLen; }
138};
139
140ast::Decl const * ReplaceTypedefCore::postvisit(
141                ast::TypedefDecl const * decl ) {
142        if ( 1 == typedefNames.count( decl->name ) &&
143                        typedefNames[ decl->name ].second == scopeLevel ) {
144                ast::Type const * t0 = decl->base;
145                ast::Type const * t1 = typedefNames[ decl->name ].first->base;
146                // Cannot redefine VLA typedefs. Note: this is slightly incorrect,
147                // because our notion of VLAs at this point in the translator is
148                // imprecise. In particular, this will disallow redefining typedefs
149                // with arrays whose dimension is an enumerator or a cast of a
150                // constant/enumerator. The effort required to fix this corner case
151                // likely outweighs the utility of allowing it.
152                if ( !ResolvExpr::typesCompatible( t0, t1 )
153                                || ast::Pass<VarLenChecker>::read( t0 )
154                                || ast::Pass<VarLenChecker>::read( t1 ) ) {
155                        SemanticError( decl->location, "Cannot redefine typedef: " + decl->name );
156                }
157        } else {
158                typedefNames[ decl->name ] =
159                        std::make_pair( TypedefDeclPtr( decl ), scopeLevel );
160        }
161
162        // When a typedef is a forward declaration:
163        // >    typedef struct screen SCREEN;
164        // the declaration portion must be retained:
165        // >    struct screen;
166        // because the expansion of the typedef is:
167        // >    void func( SCREEN * p ) -> void func( struct screen * p );
168        // hence type name "screen" must be defined.
169        // Note: qualifiers on the typedef are not used for the forward declaration.
170
171        ast::Type const * designatorType = decl->base->stripDeclarator();
172        if ( auto structType = dynamic_cast<ast::StructInstType const *>( designatorType ) ) {
173                declsToAddBefore.push_back( new ast::StructDecl(
174                        decl->location, structType->name, ast::AggregateDecl::Struct, {},
175                        decl->linkage ) );
176        } else if ( auto unionType = dynamic_cast<ast::UnionInstType const *>( designatorType ) ) {
177                declsToAddBefore.push_back( new ast::UnionDecl(
178                        decl->location, unionType->name, {}, decl->linkage ) );
179        } else if ( auto enumType = dynamic_cast<ast::EnumInstType const *>( designatorType ) ) {
180                declsToAddBefore.push_back( new ast::EnumDecl(
181                        decl->location, enumType->name, false, {}, decl->linkage,
182                        ( (enumType->base) ? enumType->base->base : nullptr )
183                        ) );
184        }
185        return ast::deepCopy( decl );
186}
187
188void ReplaceTypedefCore::previsit( ast::TypeDecl const * decl ) {
189        typedefNames.erase( decl->name );
190        typedeclNames.insert( decl->name, decl );
191}
192
193void ReplaceTypedefCore::previsit( ast::FunctionDecl const * ) {
194        GuardScope( typedefNames );
195        GuardScope( typedeclNames );
196        GuardValue( isAtFunctionTop ) = true;
197}
198
199void ReplaceTypedefCore::previsit( ast::ObjectDecl const * ) {
200        GuardScope( typedefNames );
201        GuardScope( typedeclNames );
202}
203
204ast::DeclWithType const * ReplaceTypedefCore::postvisit(
205                ast::ObjectDecl const * decl ) {
206        if ( ast::FunctionType const * type = decl->type.as<ast::FunctionType>() ) {
207                using DWTVector = std::vector<ast::ptr<ast::DeclWithType>>;
208                using DeclVector = std::vector<ast::ptr<ast::TypeDecl>>;
209                CodeLocation const & declLocation = decl->location;
210                UniqueName paramNamer( decl->name + "Param" );
211
212                // Replace the current object declaration with a function declaration.
213                ast::FunctionDecl const * newDecl = new ast::FunctionDecl(
214                        declLocation,
215                        decl->name,
216                        map_range<DeclVector>( type->forall, []( const ast::TypeInstType * inst ) {
217                                return ast::deepCopy( inst->base );
218                        } ),
219                        map_range<DWTVector>( type->assertions, []( const ast::VariableExpr * expr ) {
220                                return ast::deepCopy( expr->var );
221                        } ),
222                        map_range<DWTVector>( type->params, [&declLocation, &paramNamer]( const ast::Type * type ) {
223                                assert( type );
224                                return new ast::ObjectDecl( declLocation, paramNamer.newName(), ast::deepCopy( type ) );
225                        } ),
226                        map_range<DWTVector>( type->returns, [&declLocation, &paramNamer]( const ast::Type * type ) {
227                                assert( type );
228                                return new ast::ObjectDecl( declLocation, paramNamer.newName(), ast::deepCopy( type ) );
229                        } ),
230                        nullptr,
231                        decl->storage,
232                        decl->linkage,
233                        {/* attributes */},
234                        decl->funcSpec
235                );
236                return newDecl;
237        }
238        return decl;
239}
240
241void ReplaceTypedefCore::previsit( ast::CastExpr const * ) {
242        GuardScope( typedefNames );
243        GuardScope( typedeclNames );
244}
245
246void ReplaceTypedefCore::previsit( ast::CompoundStmt const * ) {
247        GuardScope( typedefNames );
248        GuardScope( typedeclNames );
249        GuardValue( isAtFunctionTop ) = false;
250        scopeLevel += 1;
251}
252
253void ReplaceTypedefCore::postvisit( ast::CompoundStmt const * ) {
254        scopeLevel -= 1;
255}
256
257ast::StructDecl const * ReplaceTypedefCore::previsit( ast::StructDecl const * decl ) {
258        visit_children = false;
259        addImplicitTypedef( decl );
260        return handleAggregate( decl );
261}
262
263ast::UnionDecl const * ReplaceTypedefCore::previsit( ast::UnionDecl const * decl ) {
264        visit_children = false;
265        addImplicitTypedef( decl );
266        return handleAggregate( decl );
267}
268
269void ReplaceTypedefCore::previsit( ast::EnumDecl const * decl ) {
270        addImplicitTypedef( decl );
271}
272
273void ReplaceTypedefCore::previsit( ast::TraitDecl const * ) {
274        GuardScope( typedefNames );
275        GuardScope( typedeclNames );
276}
277
278template<typename AggrDecl>
279void ReplaceTypedefCore::addImplicitTypedef( AggrDecl * aggrDecl ) {
280        if ( 0 != typedefNames.count( aggrDecl->name ) ) {
281                return;
282        }
283        ast::Type * type = nullptr;
284        if ( auto structDecl = dynamic_cast<const ast::StructDecl *>( aggrDecl ) ) {
285                type = new ast::StructInstType( structDecl->name );
286        } else if ( auto unionDecl = dynamic_cast<const ast::UnionDecl *>( aggrDecl ) ) {
287                type = new ast::UnionInstType( unionDecl->name );
288        } else if ( auto enumDecl = dynamic_cast<const ast::EnumDecl *>( aggrDecl ) ) {
289                type = new ast::EnumInstType( enumDecl->name );
290        }
291        assert( type );
292
293        TypedefDeclPtr typeDecl = new ast::TypedefDecl( aggrDecl->location,
294                aggrDecl->name, ast::Storage::Classes(), type, aggrDecl->linkage );
295        // Add the implicit typedef to the AST.
296        declsToAddBefore.push_back( ast::deepCopy( typeDecl.get() ) );
297        // Shore the name in the map of names.
298        typedefNames[ aggrDecl->name ] =
299                std::make_pair( std::move( typeDecl ), scopeLevel );
300}
301
302template<typename AggrDecl>
303AggrDecl const * ReplaceTypedefCore::handleAggregate( AggrDecl const * decl ) {
304        SemanticErrorException errors;
305
306        ValueGuard<decltype(declsToAddBefore)> oldBeforeDecls( declsToAddBefore );
307        ValueGuard<decltype(declsToAddAfter )> oldAfterDecls(  declsToAddAfter );
308        declsToAddBefore.clear();
309        declsToAddAfter.clear();
310
311        GuardScope( typedefNames );
312        GuardScope( typedeclNames );
313        decl = mutate_each( decl, &ast::AggregateDecl::params, *visitor );
314        decl = mutate_each( decl, &ast::AggregateDecl::attributes, *visitor );
315
316        auto mut = ast::mutate( decl );
317
318        std::vector<ast::ptr<ast::Decl>> members;
319        // Unroll accept_all for decl->members so that implicit typedefs for
320        // nested types are added to the aggregate body.
321        for ( ast::ptr<ast::Decl> const & member : mut->members ) {
322                assert( declsToAddAfter.empty() );
323                ast::Decl const * newMember = nullptr;
324                try {
325                        newMember = member->accept( *visitor );
326                } catch ( SemanticErrorException & e ) {
327                        errors.append( e );
328                }
329                if ( !declsToAddBefore.empty() ) {
330                        for ( auto declToAdd : declsToAddBefore ) {
331                                members.push_back( declToAdd );
332                        }
333                        declsToAddBefore.clear();
334                }
335                members.push_back( newMember );
336        }
337        assert( declsToAddAfter.empty() );
338        if ( !errors.isEmpty() ) { throw errors; }
339
340        mut->members.clear();
341        for ( auto member : members ) {
342                mut->members.push_back( member );
343        }
344
345        return mut;
346}
347
348} // namespace
349
350void replaceTypedef( ast::TranslationUnit & translationUnit ) {
351        ast::Pass<ReplaceTypedefCore> pass;
352        ast::accept_all( translationUnit, pass );
353        if ( pass.core.typedefNames.count( "size_t" ) ) {
354                translationUnit.global.sizeType =
355                        ast::deepCopy( pass.core.typedefNames["size_t"].first->base );
356        } else {
357                // Missing the global definition, default to long unsigned int.
358                // Perhaps this should be a warning instead.
359                translationUnit.global.sizeType =
360                        new ast::BasicType( ast::BasicType::LongUnsignedInt );
361        }
362}
363
364} // namespace Validate
365
366// Local Variables: //
367// tab-width: 4 //
368// mode: c++ //
369// compile-command: "make install" //
370// End: //
Note: See TracBrowser for help on using the repository browser.