source: src/Validate/ReplaceTypedef.cpp @ 640b3df

ADTast-experimental
Last change on this file since 640b3df was 21a2a7d, checked in by Andrew Beach <ajbeach@…>, 21 months ago

Replaced ScopedMap::erase with a version that should avoid the order of declaration problems and also better reflects how it is actually used.

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