source: src/Validate/ReplaceTypedef.cpp@ ac939461

Last change on this file since ac939461 was b262cb3, checked in by Andrew Beach <ajbeach@…>, 20 months ago

Unified and fixed handling of parameter attributes.

  • 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.h"
21#include "Common/UniqueName.h"
22#include "ResolvExpr/Unify.h"
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 if ( !errors.isEmpty() ) { throw errors; }
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::BasicType::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.