source: src/ControlStruct/ExceptDecl.cpp @ d923fca

Last change on this file since d923fca was 299bd989, checked in by Andrew Beach <ajbeach@…>, 3 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.