source: src/Validate/ReplaceTypedef.cpp@ 50a8aa9

ADT ast-experimental pthread-emulation qualifiedEnum
Last change on this file since 50a8aa9 was 1931bb01, checked in by Andrew Beach <ajbeach@…>, 3 years ago

Converted 'Validate A' to the new AST. There some utility changes as well.

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