source: src/Validate/ReplaceTypedef.cpp@ 11ab0b4a

Last change on this file since 11ab0b4a was b7c53a9d, checked in by Andrew Beach <ajbeach@…>, 2 years 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.