source: src/ControlStruct/ExceptDecl.cpp@ 411aa65

Last change on this file since 411aa65 was 299bd989, checked in by Andrew Beach <ajbeach@…>, 8 months ago

Looking over some virtual cast related code to reduce the forall list of type-ids down to a minimal form. You could repeat this with virtual tables, although that might conflict with some proposed features, using the same pattern.

  • Property mode set to 100644
File size: 17.0 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// ExceptDecl.cpp -- Translate "exception" and exception related declarations.
8//
9// Author : Andrew Beach
10// Created On : Tue Jul 12 15:50:00 2022
11// Last Modified By : Andrew Beach
12// Last Modified On : Fri Jan 10 15:35:55 2024
13// Update Count : 2
14//
15
16#include "ExceptDecl.hpp"
17
18#include <sstream>
19
20#include "AST/Copy.hpp"
21#include "AST/Decl.hpp"
22#include "AST/Pass.hpp"
23#include "AST/Print.hpp"
24#include "AST/Type.hpp"
25#include "Virtual/Tables.hpp"
26
27namespace ControlStruct {
28
29namespace {
30
31std::vector<ast::ptr<ast::Expr>> forallToParams(
32 std::vector<ast::ptr<ast::TypeDecl>> const & forall ) {
33 return map_range<std::vector<ast::ptr<ast::Expr>>>( forall,
34 []( ast::ptr<ast::TypeDecl> const & decl ) {
35 return new ast::TypeExpr( decl->location,
36 new ast::TypeInstType( decl->name, decl->kind ) );
37 }
38 );
39}
40
41// A slightly argumented extra constructor, adds a deepCopy.
42ast::StructInstType * namedStructInstType(
43 std::string const & name, ast::CV::Qualifiers qualifiers,
44 std::vector<ast::ptr<ast::Expr>> const & params ) {
45 ast::StructInstType * type = new ast::StructInstType( name, qualifiers );
46 for ( ast::ptr<ast::Expr> const & param : params ) {
47 type->params.push_back( ast::deepCopy( param ) );
48 }
49 return type;
50}
51
52ast::StructInstType * createExceptionInstType(
53 std::string const & exceptionName,
54 std::vector<ast::ptr<ast::Expr>> const & params ) {
55 return namedStructInstType( exceptionName, ast::CV::Qualifiers(), params );
56}
57
58ast::StructInstType * createVTableInstType(
59 std::string const & exceptionName,
60 std::vector<ast::ptr<ast::Expr>> const & params ) {
61 std::string name = Virtual::vtableTypeName( exceptionName );
62 return namedStructInstType( name, ast::CV::Const, params );
63}
64
65ast::StructInstType * createTypeIdInstType(
66 std::string const & exceptionName,
67 std::vector<ast::ptr<ast::Expr>> const & params ) {
68 std::string name = Virtual::typeIdType( exceptionName );
69 return namedStructInstType( name, ast::CV::Const, params );
70}
71
72ast::FunctionType const * createCopyFuncType(
73 std::string const & exceptionName,
74 std::vector<ast::ptr<ast::Expr>> const & params ) {
75 ast::FunctionType * type = new ast::FunctionType( ast::FixedArgs );
76 type->params.push_back( new ast::PointerType(
77 createExceptionInstType( exceptionName, params ) ) );
78 type->params.push_back( new ast::PointerType(
79 createExceptionInstType( exceptionName, params ) ) );
80 type->returns.push_back( new ast::VoidType() );
81 return type;
82}
83
84ast::FunctionType const * createDtorFuncType(
85 std::string const & exceptionName,
86 std::vector<ast::ptr<ast::Expr>> const & params ) {
87 ast::FunctionType * type = new ast::FunctionType( ast::FixedArgs );
88 type->params.push_back( new ast::ReferenceType(
89 createExceptionInstType( exceptionName, params ) ) );
90 type->returns.push_back( new ast::VoidType() );
91 return type;
92}
93
94ast::FunctionType const * createMsgFuncType(
95 std::string const & exceptionName,
96 std::vector<ast::ptr<ast::Expr>> const & params ) {
97 ast::FunctionType * type = new ast::FunctionType( ast::FixedArgs );
98 type->params.push_back( new ast::PointerType(
99 createExceptionInstType( exceptionName, params ) ) );
100 type->returns.push_back( new ast::PointerType(
101 new ast::BasicType( ast::BasicKind::Char, ast::CV::Const ) ) );
102 return type;
103}
104
105ast::StructDecl const * createTypeIdStruct(
106 CodeLocation const & location,
107 std::string const & exceptionName,
108 std::vector<ast::ptr<ast::TypeDecl>> const & forallClause ) {
109 ast::StructDecl * decl = new ast::StructDecl( location,
110 Virtual::typeIdType( exceptionName ) );
111 decl->members.push_back( new ast::ObjectDecl(
112 location,
113 "parent",
114 new ast::PointerType(
115 new ast::StructInstType( "__cfavir_type_info", ast::CV::Const ) )
116 ) );
117 decl->body = true;
118 for ( ast::ptr<ast::TypeDecl> const & param : forallClause ) {
119 // Create an unsized and assertionless copy of the parameter.
120 decl->params.push_back( new ast::TypeDecl(
121 param->location,
122 param->name,
123 param->storage,
124 param->base ? ast::deepCopy( param->base ) : nullptr,
125 ast::TypeDecl::Dtype,
126 false,
127 nullptr
128 ) );
129 }
130 return decl;
131}
132
133ast::ObjectDecl const * createTypeIdValue(
134 CodeLocation const & location,
135 std::string const & exceptionName,
136 std::vector<ast::ptr<ast::Expr>> const & params ) {
137 ast::StructInstType * typeIdType =
138 createTypeIdInstType( exceptionName, params );
139 return new ast::ObjectDecl(
140 location,
141 Virtual::typeIdName( exceptionName ),
142 typeIdType,
143 new ast::ListInit( location, {
144 new ast::SingleInit( location,
145 new ast::AddressExpr( location,
146 new ast::NameExpr( location, "__cfatid_exception_t" ) ),
147 ast::MaybeConstruct ),
148 }, {}, ast::MaybeConstruct ),
149 ast::Storage::Classes(),
150 ast::Linkage::Cforall,
151 nullptr,
152 { new ast::Attribute( "cfa_linkonce" ) }
153 );
154}
155
156ast::StructDecl const * createExceptionStructForward(
157 CodeLocation const & location,
158 std::string const & exceptionName,
159 std::vector<ast::ptr<ast::TypeDecl>> const & forall ) {
160 ast::StructDecl * decl = new ast::StructDecl( location, exceptionName );
161 for ( ast::ptr<ast::TypeDecl> const & param : forall ) {
162 decl->params.push_back( ast::deepCopy( param ) );
163 }
164 return decl;
165}
166
167ast::StructDecl const * createVirtualTableStruct(
168 CodeLocation const & location,
169 std::string const & exceptionName,
170 std::vector<ast::ptr<ast::TypeDecl>> const & forall,
171 std::vector<ast::ptr<ast::Expr>> const & params ) {
172 ast::StructInstType * typeIdType =
173 createTypeIdInstType( exceptionName, params );
174 ast::ObjectDecl * typeId = new ast::ObjectDecl(
175 location,
176 "__cfavir_typeid",
177 new ast::PointerType( typeIdType )
178 );
179 ast::ObjectDecl * size = new ast::ObjectDecl(
180 location,
181 "size",
182 new ast::TypeInstType( "size_t", ast::TypeDecl::Dtype )
183 );
184 ast::ObjectDecl * copy = new ast::ObjectDecl(
185 location,
186 "copy",
187 new ast::PointerType( createCopyFuncType( exceptionName, params ) )
188 );
189 ast::ObjectDecl * dtor = new ast::ObjectDecl(
190 location,
191 "^?{}",
192 new ast::PointerType( createDtorFuncType( exceptionName, params ) )
193 );
194 ast::ObjectDecl * msg = new ast::ObjectDecl(
195 location,
196 "msg",
197 new ast::PointerType( createMsgFuncType( exceptionName, params ) )
198 );
199 ast::StructDecl * decl = new ast::StructDecl(
200 location,
201 Virtual::vtableTypeName( exceptionName ) );
202 decl->members.push_back( typeId );
203 decl->members.push_back( size );
204 decl->members.push_back( copy );
205 decl->members.push_back( dtor );
206 decl->members.push_back( msg );
207 decl->body = true;
208 for ( ast::ptr<ast::TypeDecl> const & param : forall ) {
209 decl->params.push_back( param );
210 }
211 return decl;
212}
213
214ast::StructDecl const * createExceptionStruct(
215 CodeLocation const & location,
216 std::string const & exceptionName,
217 std::vector<ast::ptr<ast::TypeDecl>> const & forallClause,
218 std::vector<ast::ptr<ast::Expr>> const & params,
219 std::vector<ast::ptr<ast::Decl>> const & members ) {
220 ast::StructDecl * decl = new ast::StructDecl( location, exceptionName );
221 decl->members.push_back( new ast::ObjectDecl(
222 location,
223 "virtual_table",
224 new ast::PointerType(
225 createVTableInstType( exceptionName, params ) )
226 ) );
227 for ( ast::ptr<ast::Decl> const & member : members ) {
228 decl->members.push_back( ast::deepCopy( member ) );
229 }
230 decl->body = true;
231 for ( ast::ptr<ast::TypeDecl> const & param : forallClause ) {
232 decl->params.push_back( ast::deepCopy( param ) );
233 }
234 return decl;
235}
236
237ast::ObjectDecl const * createExternTypeId(
238 CodeLocation const & location,
239 std::string const & exceptionName,
240 std::vector<ast::ptr<ast::Expr>> const & params ) {
241 return new ast::ObjectDecl(
242 location,
243 Virtual::typeIdName( exceptionName ),
244 createVTableInstType( exceptionName, params ),
245 nullptr,
246 ast::Storage::Extern,
247 ast::Linkage::Cforall,
248 nullptr,
249 { new ast::Attribute( "cfa_linkonce" ) }
250 );
251}
252
253ast::ObjectDecl * createExternVTable(
254 CodeLocation const & location,
255 std::string const & exceptionName,
256 std::vector<ast::ptr<ast::Expr>> const & params,
257 std::string const & tableName ) {
258 return new ast::ObjectDecl(
259 location,
260 tableName,
261 createVTableInstType( exceptionName, params ),
262 nullptr,
263 ast::Storage::Extern,
264 ast::Linkage::Cforall
265 );
266}
267
268ast::FunctionDecl const * createCopy(
269 CodeLocation const & location,
270 std::string const & exceptionName,
271 std::vector<ast::ptr<ast::Expr>> const & params ) {
272 return new ast::FunctionDecl(
273 location,
274 "copy",
275 {/* forall */},
276 {/* assertions */},
277 {
278 new ast::ObjectDecl(
279 location,
280 "this",
281 new ast::PointerType(
282 createExceptionInstType( exceptionName, params ) )
283 ),
284 new ast::ObjectDecl(
285 location,
286 "that",
287 new ast::PointerType(
288 createExceptionInstType( exceptionName, params ) )
289 ),
290 },
291 {
292 new ast::ObjectDecl( location, "", new ast::VoidType() ),
293 },
294 new ast::CompoundStmt( location, {
295 new ast::ExprStmt( location,
296 new ast::UntypedExpr( location,
297 new ast::NameExpr( location, "?{}" ),
298 {
299 new ast::UntypedExpr( location,
300 new ast::NameExpr( location, "*?" ),
301 { new ast::NameExpr( location, "this" ) } ),
302 new ast::UntypedExpr( location,
303 new ast::NameExpr( location, "*?" ),
304 { new ast::NameExpr( location, "that" ) } ),
305 }
306 )
307 ),
308 } ),
309 ast::Storage::Classes(),
310 ast::Linkage::Cforall,
311 { new ast::Attribute( "cfa_linkonce" ) }
312 );
313}
314
315ast::FunctionDecl const * createMsg(
316 CodeLocation const & location,
317 std::string const & exceptionName,
318 std::vector<ast::ptr<ast::Expr>> const & params ) {
319 std::stringstream msg;
320 msg << exceptionName;
321 // The forall variant, add parameters to the string.
322 if ( !params.empty() ) {
323 msg << "(";
324 bool first = true;
325 for ( auto & param : params ) {
326 // Seperator Logic: A comma proceeds all but the first object.
327 if ( first ) {
328 first = false;
329 } else {
330 msg << ", ";
331 }
332
333 ast::print( msg, param.get() );
334 }
335 msg << ")";
336 }
337 return new ast::FunctionDecl(
338 location,
339 "msg",
340 {/* forall */},
341 {/* assertions */},
342 {
343 new ast::ObjectDecl(
344 location,
345 "", // "this," though unused in the body
346 new ast::PointerType(
347 createExceptionInstType( exceptionName, params ) )
348 ),
349 },
350 {
351 new ast::ObjectDecl(
352 location,
353 "",
354 new ast::PointerType(
355 new ast::BasicType( ast::BasicKind::Char, ast::CV::Const ) )
356 ),
357 },
358 new ast::CompoundStmt( location, {
359 new ast::ReturnStmt( location,
360 ast::ConstantExpr::from_string( location, msg.str() )
361 ),
362 } ),
363 ast::Storage::Classes(),
364 ast::Linkage::Cforall,
365 { new ast::Attribute( "cfa_linkonce" ) }
366 );
367}
368
369ast::ObjectDecl * createVirtualTable(
370 CodeLocation const & location,
371 std::string const & exceptionName,
372 std::vector<ast::ptr<ast::Expr>> const & params,
373 std::string const & tableName ) {
374 ast::StructInstType * sizeType = new ast::StructInstType( exceptionName );
375 for ( ast::ptr<ast::Expr> const & param : params ) {
376 sizeType->params.push_back( ast::deepCopy( param ) );
377 }
378 std::vector<ast::ptr<ast::Init>> inits {
379 new ast::SingleInit( location,
380 new ast::AddressExpr( location,
381 new ast::NameExpr( location,
382 Virtual::typeIdName( exceptionName ) ) ) ),
383 new ast::SingleInit( location,
384 new ast::SizeofExpr( location, sizeType ) ),
385 new ast::SingleInit( location,
386 new ast::NameExpr( location, "copy" ) ),
387 new ast::SingleInit( location,
388 new ast::NameExpr( location, "^?{}" ) ),
389 new ast::SingleInit( location,
390 new ast::NameExpr( location, "msg" ) ),
391 };
392 std::vector<ast::ptr<ast::Designation>> dsigs {
393 new ast::Designation( location, {
394 new ast::NameExpr( location, "__cfavir_typeid" ) } ),
395 new ast::Designation( location, {
396 new ast::NameExpr( location, "size" ) } ),
397 new ast::Designation( location, {
398 new ast::NameExpr( location, "copy" ) } ),
399 new ast::Designation( location, {
400 new ast::NameExpr( location, "^?{}" ) } ),
401 new ast::Designation( location, {
402 new ast::NameExpr( location, "msg" ) } ),
403 };
404 return new ast::ObjectDecl(
405 location,
406 tableName,
407 createVTableInstType( exceptionName, params ),
408 new ast::ListInit( location, std::move( inits ), std::move( dsigs ) )
409 );
410}
411
412struct ExceptDeclCore : public ast::WithDeclsToAdd {
413 ast::StructDecl const * transformExcept( ast::StructDecl const * decl );
414 ast::ObjectDecl const * transformVTable(
415 ast::ObjectDecl const * decl, ast::VTableType const * type );
416
417 ast::StructDecl const * postvisit( ast::StructDecl const * decl ) {
418 // Exceptions don't get their own node type, so filter that.
419 if ( ast::AggregateDecl::Exception == decl->kind ) {
420 return transformExcept( decl );
421 }
422 return decl;
423 }
424
425 ast::ObjectDecl const * postvisit( ast::ObjectDecl const * decl ) {
426 // Modify remaining objects that have a vtable type.
427 if ( auto * type = decl->type.as<ast::VTableType>() ) {
428 return transformVTable( decl, type );
429 }
430 return decl;
431 }
432};
433
434ast::StructDecl const * ExceptDeclCore::transformExcept(
435 ast::StructDecl const * decl ) {
436 CodeLocation const & location = decl->location;
437 std::string const & exceptionName = decl->name;
438 std::vector<ast::ptr<ast::TypeDecl>> const & forall = decl->params;
439 std::vector<ast::ptr<ast::Expr>> params = forallToParams( forall );
440 std::vector<ast::ptr<ast::Decl>> const & members = decl->members;
441
442 declsToAddBefore.push_back(
443 createTypeIdStruct( location, exceptionName, forall ) );
444 if ( forall.empty() ) {
445 // Non-forall variant.
446 declsToAddBefore.push_back(
447 createTypeIdValue( location, exceptionName, params ) );
448 }
449 declsToAddBefore.push_back(
450 createExceptionStructForward( location, exceptionName, forall ) );
451 declsToAddBefore.push_back(
452 createVirtualTableStruct( location, exceptionName, forall, params ) );
453 return createExceptionStruct( location, exceptionName, forall, params, members );
454}
455
456ast::NameExpr const * designatedName( ast::Designation const * des ) {
457 if ( des && 1 == des->designators.size() ) {
458 return des->designators.front().as<ast::NameExpr>();
459 }
460 return nullptr;
461}
462
463ast::ObjectDecl const * ExceptDeclCore::transformVTable(
464 ast::ObjectDecl const * decl, ast::VTableType const * type ) {
465 CodeLocation const & location = decl->location;
466 auto base = type->base.strict_as<ast::TypeInstType>();
467 std::string const & exceptionName = base->name;
468 std::vector<ast::ptr<ast::Expr>> const & params = base->params;
469 std::string const & tableName = decl->name;
470
471 ast::ObjectDecl * retDecl;
472 if ( decl->storage.is_extern ) {
473 // Unique type-ids are only needed for polymorphic instances.
474 if ( !params.empty() ) {
475 declsToAddBefore.push_back(
476 createExternTypeId( location, exceptionName, params ) );
477 }
478 retDecl = createExternVTable( location, exceptionName, params, tableName );
479 } else {
480 // Unique type-ids are only needed for polymorphic instances.
481 if ( !params.empty() ) {
482 declsToAddBefore.push_back(
483 createTypeIdValue( location, exceptionName, params ) );
484 }
485 retDecl = createVirtualTable(
486 location, exceptionName, params, tableName );
487 // There is quite a bit of work to pull over any initializers and
488 // decide if we want to insert the default functions.
489 bool foundCopy = false;
490 bool foundMsg = false;
491 ast::ListInit const * init = decl->init.as<ast::ListInit>();
492 if ( init ) {
493 for ( size_t i = 0 ; i < init->initializers.size() ; ++i ) {
494 ast::Designation const * des = init->designations.at(i);
495 auto name = designatedName( des );
496 if ( nullptr == name ) continue;
497 if ( "copy" == name->name ) {
498 foundCopy = true;
499 } else if ( "msg" == name->name ) {
500 foundMsg = true;
501 }
502 auto retInit = retDecl->init.as<ast::ListInit>();
503 for ( size_t j = 0 ; j < retInit->initializers.size() ; ++j ) {
504 ast::Designation const * des = retInit->designations.at(j);
505 auto retName = designatedName( des );
506 if ( retName && name->name == retName->name ) {
507 retInit = ast::mutate_field_index( retInit,
508 &ast::ListInit::initializers, j,
509 init->initializers.at(i) );
510 }
511 }
512 retDecl->init = retInit;
513 }
514 }
515 if ( !foundCopy ) {
516 declsToAddBefore.push_back(
517 createCopy( location, exceptionName, params ) );
518 }
519 if ( !foundMsg ) {
520 declsToAddBefore.push_back(
521 createMsg( location, exceptionName, params ) );
522 }
523 }
524
525 for ( ast::ptr<ast::Attribute> const & attr : decl->attributes ) {
526 retDecl->attributes.push_back( attr );
527 }
528
529 return retDecl;
530}
531
532struct VTableCore {
533 ast::StructInstType const * postvisit( ast::VTableType const * type ) {
534 auto inst = type->base.as<ast::BaseInstType>();
535
536 std::string vtableName = Virtual::vtableTypeName( inst->name );
537
538 auto newType = new ast::StructInstType( vtableName );
539 for ( ast::ptr<ast::Expr> const & param : inst->params ) {
540 newType->params.push_back( param );
541 }
542
543 return newType;
544 }
545};
546
547} // namespace
548
549void translateExcept( ast::TranslationUnit & translationUnit ) {
550 // Can I combine these?
551 // Second pass really only covers what the first has missed.
552 // Maybe if the first one is all previsits and the second all postvisit.
553 ast::Pass<ExceptDeclCore>::run( translationUnit );
554 ast::Pass<VTableCore>::run( translationUnit );
555}
556
557} // namespace ControlStruct
558
559// Local Variables: //
560// tab-width: 4 //
561// mode: c++ //
562// compile-command: "make install" //
563// End: //
Note: See TracBrowser for help on using the repository browser.