source: src/Validate/ReplaceTypedef.cpp@ dcf8054

Last change on this file since dcf8054 was 4167afa, checked in by Peter A. Buhr <pabuhr@…>, 9 months 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.