source: src/Validate/ReplaceTypedef.cpp @ f54e6ec

Last change on this file since f54e6ec was b7c53a9d, checked in by Andrew Beach <ajbeach@…>, 16 months ago

Added a new invariant check and the fixes required to make it pass. Not the new check is by no means exaustive (it doesn't even check every readonly pointer) but it should catch the most common/problematic cases.

  • Property mode set to 100644
File size: 12.4 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 "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 )
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        declsToAddAfter.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::list<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( declsToAddBefore.empty() );
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                        members.splice( members.end(), declsToAddBefore );
331                }
332                members.push_back( newMember );
333                if ( !declsToAddAfter.empty() ) {
334                        members.splice( members.end(), declsToAddAfter );
335                }
336        }
337        assert( declsToAddBefore.empty() );
338        assert( declsToAddAfter.empty() );
339        if ( !errors.isEmpty() ) { throw errors; }
340
341        mut->members.clear();
342        for ( auto member : members ) {
343                mut->members.push_back( member );
344        }
345
346        return mut;
347}
348
349} // namespace
350
351void replaceTypedef( ast::TranslationUnit & translationUnit ) {
352        ast::Pass<ReplaceTypedefCore> pass;
353        ast::accept_all( translationUnit, pass );
354        if ( pass.core.typedefNames.count( "size_t" ) ) {
355                translationUnit.global.sizeType =
356                        ast::deepCopy( pass.core.typedefNames["size_t"].first->base );
357        } else {
358                // Missing the global definition, default to long unsigned int.
359                // Perhaps this should be a warning instead.
360                translationUnit.global.sizeType =
361                        new ast::BasicType( ast::BasicType::LongUnsignedInt );
362        }
363}
364
365} // namespace Validate
366
367// Local Variables: //
368// tab-width: 4 //
369// mode: c++ //
370// compile-command: "make install" //
371// End: //
Note: See TracBrowser for help on using the repository browser.