source: src/Validate/ReplaceTypedef.cpp @ 720eec9

Last change on this file since 720eec9 was 16ba4897, checked in by Andrew Beach <ajbeach@…>, 6 weeks ago

Replaced SemanticErrorException::isEmpty with ...::throwIfNonEmpty. This is how it was used in every context and it saves a bit of text (if not two lines) at every use. I considered putting this function in the header for better inlining, but this should have at least the same preformance as the last version.

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