source: src/Validate/ReplaceTypedef.cpp @ 4167afa

Last change on this file since 4167afa was 4167afa, checked in by Peter A. Buhr <pabuhr@…>, 39 hours ago

remove superflous calls to std::move

  • Property mode set to 100644
File size: 13.6 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 : Mon Dec 16 20:50:42 2024
13// Update Count     : 5
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}
122struct VarLenChecker : public ast::WithShortCircuiting {
123        bool result = false;
124        void previsit( ast::FunctionType const * ) { visit_children = false; }
125        void previsit( ast::ArrayType const * at ) { result |= at->isVarLen; }
126};
127static bool hasVarLen( const ast::Type * t ) {
128        return ast::Pass<VarLenChecker>::read( t );
129}
130struct ArrayTypeExtractor {
131        std::vector<const ast::ArrayType *> result;
132        void postvisit( const ast::ArrayType * at ) {
133                result.push_back( at );
134        }
135};
136static bool dimensionPresenceMismatched( const ast::Type * t0, const ast::Type * t1) {
137        std::vector<const ast::ArrayType *> at0s = ast::Pass<ArrayTypeExtractor>::read( t0 );
138        std::vector<const ast::ArrayType *> at1s = ast::Pass<ArrayTypeExtractor>::read( t1 );
139        assert( at0s.size() == at1s.size() );
140        for (size_t i = 0; i < at0s.size(); i++) {
141                const ast::ArrayType * at0 = at0s[i];
142                const ast::ArrayType * at1 = at1s[i];
143                assert( ResolvExpr::typesCompatible( at0, at1 ) );
144                if ( (at0->dimension != nullptr) != (at1->dimension != nullptr) ) return true;
145        }
146        return false;
147}
148ast::Decl const * ReplaceTypedefCore::postvisit(
149                ast::TypedefDecl const * decl ) {
150        if ( 1 == typedefNames.count( decl->name ) &&
151                        typedefNames[ decl->name ].second == scopeLevel ) {
152                ast::Type const * t0 = decl->base;
153                ast::Type const * t1 = typedefNames[ decl->name ].first->base;
154                // [hasVarLen]
155                // Cannot redefine VLA typedefs. Note: this is slightly incorrect,
156                // because our notion of VLAs at this point in the translator is
157                // imprecise. In particular, this will disallow redefining typedefs
158                // with arrays whose dimension is an enumerator or a cast of a
159                // constant/enumerator. The effort required to fix this corner case
160                // likely outweighs the utility of allowing it.
161                // [dimensionPresenceMismatched]
162                // Core typesCompatible logic interprets absent dimensions as wildcards,
163                // i.e. float[][*] matches float[][42].
164                // For detecting incompatible typedefs, we have to interpret them verbatim,
165                // i.e. float[] is different than float[42].
166                // But typesCompatible does assure that the pair of types is structurally
167                // consistent, outside of the dimension expressions.  This assurance guards
168                // the dimension-presence traversal.  So this traversal logic can (and does)
169                // assume that ArrayTypes will be encountered in analogous places.
170                if ( !ResolvExpr::typesCompatible( t0, t1 )
171                                || hasVarLen( t0 )
172                                || hasVarLen( t1 )
173                                || dimensionPresenceMismatched( t0, t1 ) ) {
174                        SemanticError( decl->location, "Cannot redefine typedef %s", decl->name.c_str() );
175                }
176        } else {
177                typedefNames[ decl->name ] =
178                        std::make_pair( TypedefDeclPtr( decl ), scopeLevel );
179        }
180
181        // When a typedef is a forward declaration:
182        // >    typedef struct screen SCREEN;
183        // the declaration portion must be retained:
184        // >    struct screen;
185        // because the expansion of the typedef is:
186        // >    void func( SCREEN * p ) -> void func( struct screen * p );
187        // hence type name "screen" must be defined.
188        // Note: qualifiers on the typedef are not used for the forward declaration.
189
190        ast::Type const * designatorType = decl->base->stripDeclarator();
191        if ( auto structType = dynamic_cast<ast::StructInstType const *>( designatorType ) ) {
192                declsToAddBefore.push_back( new ast::StructDecl(
193                        decl->location, structType->name, ast::AggregateDecl::Struct, {},
194                        decl->linkage ) );
195        } else if ( auto unionType = dynamic_cast<ast::UnionInstType const *>( designatorType ) ) {
196                declsToAddBefore.push_back( new ast::UnionDecl(
197                        decl->location, unionType->name, {}, decl->linkage ) );
198        } else if ( auto enumType = dynamic_cast<ast::EnumInstType const *>( designatorType ) ) {
199                declsToAddBefore.push_back( new ast::EnumDecl(
200                        decl->location, enumType->name, false, {}, decl->linkage,
201                        ( (enumType->base) ? enumType->base->base : nullptr )
202                        ) );
203        }
204        return ast::deepCopy( decl );
205}
206
207void ReplaceTypedefCore::previsit( ast::TypeDecl const * decl ) {
208        typedefNames.erase( decl->name );
209        typedeclNames.insert( decl->name, decl );
210}
211
212void ReplaceTypedefCore::previsit( ast::FunctionDecl const * ) {
213        GuardScope( typedefNames );
214        GuardScope( typedeclNames );
215        GuardValue( isAtFunctionTop ) = true;
216}
217
218void ReplaceTypedefCore::previsit( ast::ObjectDecl const * ) {
219        GuardScope( typedefNames );
220        GuardScope( typedeclNames );
221}
222
223ast::DeclWithType const * ReplaceTypedefCore::postvisit(
224                ast::ObjectDecl const * decl ) {
225        if ( ast::FunctionType const * type = decl->type.as<ast::FunctionType>() ) {
226                using DWTVector = std::vector<ast::ptr<ast::DeclWithType>>;
227                using DeclVector = std::vector<ast::ptr<ast::TypeDecl>>;
228                CodeLocation const & declLocation = decl->location;
229                UniqueName paramNamer( decl->name + "Param" );
230
231                // Replace the current object declaration with a function declaration.
232                ast::FunctionDecl const * newDecl = new ast::FunctionDecl(
233                        declLocation,
234                        decl->name,
235                        map_range<DeclVector>( type->forall, []( const ast::TypeInstType * inst ) {
236                                return ast::deepCopy( inst->base );
237                        } ),
238                        map_range<DWTVector>( type->assertions, []( const ast::VariableExpr * expr ) {
239                                return ast::deepCopy( expr->var );
240                        } ),
241                        map_range<DWTVector>( type->params, [&declLocation, &paramNamer]( const ast::Type * type ) {
242                                assert( type );
243                                return new ast::ObjectDecl( declLocation, paramNamer.newName(), ast::deepCopy( type ) );
244                        } ),
245                        map_range<DWTVector>( type->returns, [&declLocation, &paramNamer]( const ast::Type * type ) {
246                                assert( type );
247                                return new ast::ObjectDecl( declLocation, paramNamer.newName(), ast::deepCopy( type ) );
248                        } ),
249                        nullptr,
250                        decl->storage,
251                        decl->linkage,
252                        {/* attributes */},
253                        decl->funcSpec
254                );
255                return newDecl;
256        }
257        return decl;
258}
259
260void ReplaceTypedefCore::previsit( ast::CastExpr const * ) {
261        GuardScope( typedefNames );
262        GuardScope( typedeclNames );
263}
264
265void ReplaceTypedefCore::previsit( ast::CompoundStmt const * ) {
266        GuardScope( typedefNames );
267        GuardScope( typedeclNames );
268        GuardValue( isAtFunctionTop ) = false;
269        scopeLevel += 1;
270}
271
272void ReplaceTypedefCore::postvisit( ast::CompoundStmt const * ) {
273        scopeLevel -= 1;
274}
275
276ast::StructDecl const * ReplaceTypedefCore::previsit( ast::StructDecl const * decl ) {
277        visit_children = false;
278        addImplicitTypedef( decl );
279        return handleAggregate( decl );
280}
281
282ast::UnionDecl const * ReplaceTypedefCore::previsit( ast::UnionDecl const * decl ) {
283        visit_children = false;
284        addImplicitTypedef( decl );
285        return handleAggregate( decl );
286}
287
288void ReplaceTypedefCore::previsit( ast::EnumDecl const * decl ) {
289        addImplicitTypedef( decl );
290}
291
292void ReplaceTypedefCore::previsit( ast::TraitDecl const * ) {
293        GuardScope( typedefNames );
294        GuardScope( typedeclNames );
295}
296
297template<typename AggrDecl>
298void ReplaceTypedefCore::addImplicitTypedef( AggrDecl * aggrDecl ) {
299        if ( 0 != typedefNames.count( aggrDecl->name ) ) {
300                return;
301        }
302        ast::Type * type = nullptr;
303        if ( auto structDecl = dynamic_cast<const ast::StructDecl *>( aggrDecl ) ) {
304                type = new ast::StructInstType( structDecl->name );
305        } else if ( auto unionDecl = dynamic_cast<const ast::UnionDecl *>( aggrDecl ) ) {
306                type = new ast::UnionInstType( unionDecl->name );
307        } else if ( auto enumDecl = dynamic_cast<const ast::EnumDecl *>( aggrDecl ) ) {
308                type = new ast::EnumInstType( enumDecl->name );
309        }
310        assert( type );
311
312        TypedefDeclPtr typeDecl = new ast::TypedefDecl( aggrDecl->location,
313                aggrDecl->name, ast::Storage::Classes(), type, aggrDecl->linkage );
314        // Add the implicit typedef to the AST.
315        declsToAddAfter.push_back( ast::deepCopy( typeDecl.get() ) );
316        // Shore the name in the map of names.
317        typedefNames[ aggrDecl->name ] =
318                std::make_pair( std::move( typeDecl ), scopeLevel );
319}
320
321template<typename AggrDecl>
322AggrDecl const * ReplaceTypedefCore::handleAggregate( AggrDecl const * decl ) {
323        SemanticErrorException errors;
324
325        ValueGuard<decltype(declsToAddBefore)> oldBeforeDecls( declsToAddBefore );
326        ValueGuard<decltype(declsToAddAfter )> oldAfterDecls(  declsToAddAfter );
327        declsToAddBefore.clear();
328        declsToAddAfter.clear();
329
330        GuardScope( typedefNames );
331        GuardScope( typedeclNames );
332        decl = mutate_each( decl, &ast::AggregateDecl::params, *visitor );
333        decl = mutate_each( decl, &ast::AggregateDecl::attributes, *visitor );
334
335        auto mut = ast::mutate( decl );
336
337        std::list<ast::ptr<ast::Decl>> members;
338        // Unroll accept_all for decl->members so that implicit typedefs for
339        // nested types are added to the aggregate body.
340        for ( ast::ptr<ast::Decl> const & member : mut->members ) {
341                assert( declsToAddBefore.empty() );
342                assert( declsToAddAfter.empty() );
343                ast::Decl const * newMember = nullptr;
344                try {
345                        newMember = member->accept( *visitor );
346                } catch ( SemanticErrorException & e ) {
347                        errors.append( e );
348                }
349                if ( !declsToAddBefore.empty() ) {
350                        members.splice( members.end(), declsToAddBefore );
351                }
352                members.push_back( newMember );
353                if ( !declsToAddAfter.empty() ) {
354                        members.splice( members.end(), declsToAddAfter );
355                }
356        }
357        assert( declsToAddBefore.empty() );
358        assert( declsToAddAfter.empty() );
359        errors.throwIfNonEmpty();
360
361        mut->members.clear();
362        for ( auto member : members ) {
363                mut->members.push_back( member );
364        }
365
366        return mut;
367}
368
369} // namespace
370
371void replaceTypedef( ast::TranslationUnit & translationUnit ) {
372        ast::Pass<ReplaceTypedefCore> pass;
373        ast::accept_all( translationUnit, pass );
374        if ( pass.core.typedefNames.count( "size_t" ) ) {
375                translationUnit.global.sizeType =
376                        ast::deepCopy( pass.core.typedefNames["size_t"].first->base );
377        } else {
378                // Missing the global definition, default to long unsigned int.
379                // Perhaps this should be a warning instead.
380                translationUnit.global.sizeType =
381                        new ast::BasicType( ast::BasicKind::LongUnsignedInt );
382        }
383}
384
385} // namespace Validate
386
387// Local Variables: //
388// tab-width: 4 //
389// mode: c++ //
390// compile-command: "make install" //
391// End: //
Note: See TracBrowser for help on using the repository browser.