// // Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo // // The contents of this file are covered under the licence agreement in the // file "LICENCE" distributed with Cforall. // // ExceptDecl.cpp -- // // Author : Andrew Beach // Created On : Tue Jul 12 15:50:00 2022 // Last Modified By : Peter A. Buhr // Last Modified On : Sat Sep 7 12:05:55 2024 // Update Count : 1 // #include "ExceptDecl.hpp" #include #include "AST/Copy.hpp" #include "AST/Decl.hpp" #include "AST/Pass.hpp" #include "AST/Print.hpp" #include "AST/Type.hpp" #include "Virtual/Tables.hpp" namespace ControlStruct { namespace { std::vector> forallToParams( std::vector> const & forall ) { return map_range>>( forall, []( ast::ptr const & decl ) { return new ast::TypeExpr( decl->location, new ast::TypeInstType( decl->name, decl->kind ) ); } ); } // A slightly argumented extra constructor, adds a deepCopy. ast::StructInstType * namedStructInstType( std::string const & name, ast::CV::Qualifiers qualifiers, std::vector> const & params ) { ast::StructInstType * type = new ast::StructInstType( name, qualifiers ); for ( ast::ptr const & param : params ) { type->params.push_back( ast::deepCopy( param ) ); } return type; } ast::StructInstType * createExceptionInstType( std::string const & exceptionName, std::vector> const & params ) { return namedStructInstType( exceptionName, ast::CV::Qualifiers(), params ); } ast::StructInstType * createVTableInstType( std::string const & exceptionName, std::vector> const & params ) { std::string name = Virtual::vtableTypeName( exceptionName ); return namedStructInstType( name, ast::CV::Const, params ); } ast::StructInstType * createTypeIdInstType( std::string const & exceptionName, std::vector> const & params ) { std::string name = Virtual::typeIdType( exceptionName ); return namedStructInstType( name, ast::CV::Const, params ); } ast::FunctionType const * createCopyFuncType( std::string const & exceptionName, std::vector> const & params ) { ast::FunctionType * type = new ast::FunctionType( ast::FixedArgs ); type->params.push_back( new ast::PointerType( createExceptionInstType( exceptionName, params ) ) ); type->params.push_back( new ast::PointerType( createExceptionInstType( exceptionName, params ) ) ); type->returns.push_back( new ast::VoidType() ); return type; } ast::FunctionType const * createDtorFuncType( std::string const & exceptionName, std::vector> const & params ) { ast::FunctionType * type = new ast::FunctionType( ast::FixedArgs ); type->params.push_back( new ast::ReferenceType( createExceptionInstType( exceptionName, params ) ) ); type->returns.push_back( new ast::VoidType() ); return type; } ast::FunctionType const * createMsgFuncType( std::string const & exceptionName, std::vector> const & params ) { ast::FunctionType * type = new ast::FunctionType( ast::FixedArgs ); type->params.push_back( new ast::PointerType( createExceptionInstType( exceptionName, params ) ) ); type->returns.push_back( new ast::PointerType( new ast::BasicType( ast::BasicKind::Char, ast::CV::Const ) ) ); return type; } ast::StructDecl const * createTypeIdStruct( CodeLocation const & location, std::string const & exceptionName, std::vector> const & forallClause ) { ast::StructDecl * decl = new ast::StructDecl( location, Virtual::typeIdType( exceptionName ) ); decl->members.push_back( new ast::ObjectDecl( location, "parent", new ast::PointerType( new ast::StructInstType( "__cfavir_type_info", ast::CV::Const ) ) ) ); decl->body = true; for ( ast::ptr const & param : forallClause ) { decl->params.push_back( ast::deepCopy( param ) ); } return decl; } ast::ObjectDecl const * createTypeIdValue( CodeLocation const & location, std::string const & exceptionName, std::vector> const & params ) { ast::StructInstType * typeIdType = createTypeIdInstType( exceptionName, params ); return new ast::ObjectDecl( location, Virtual::typeIdName( exceptionName ), typeIdType, new ast::ListInit( location, { new ast::SingleInit( location, new ast::AddressExpr( location, new ast::NameExpr( location, "__cfatid_exception_t" ) ), ast::MaybeConstruct ), }, {}, ast::MaybeConstruct ), ast::Storage::Classes(), ast::Linkage::Cforall, nullptr, { new ast::Attribute( "cfa_linkonce" ) } ); } ast::StructDecl const * createExceptionStructForward( CodeLocation const & location, std::string const & exceptionName, std::vector> const & forall ) { ast::StructDecl * decl = new ast::StructDecl( location, exceptionName ); for ( ast::ptr const & param : forall ) { decl->params.push_back( ast::deepCopy( param ) ); } return decl; } ast::StructDecl const * createVirtualTableStruct( CodeLocation const & location, std::string const & exceptionName, std::vector> const & forall, std::vector> const & params ) { ast::StructInstType * typeIdType = createTypeIdInstType( exceptionName, params ); ast::ObjectDecl * typeId = new ast::ObjectDecl( location, "__cfavir_typeid", new ast::PointerType( typeIdType ) ); ast::ObjectDecl * size = new ast::ObjectDecl( location, "size", new ast::TypeInstType( "size_t", ast::TypeDecl::Dtype ) ); ast::ObjectDecl * copy = new ast::ObjectDecl( location, "copy", new ast::PointerType( createCopyFuncType( exceptionName, params ) ) ); ast::ObjectDecl * dtor = new ast::ObjectDecl( location, "^?{}", new ast::PointerType( createDtorFuncType( exceptionName, params ) ) ); ast::ObjectDecl * msg = new ast::ObjectDecl( location, "msg", new ast::PointerType( createMsgFuncType( exceptionName, params ) ) ); ast::StructDecl * decl = new ast::StructDecl( location, Virtual::vtableTypeName( exceptionName ) ); decl->members.push_back( typeId ); decl->members.push_back( size ); decl->members.push_back( copy ); decl->members.push_back( dtor ); decl->members.push_back( msg ); decl->body = true; for ( ast::ptr const & param : forall ) { decl->params.push_back( param ); } return decl; } ast::StructDecl const * createExceptionStruct( CodeLocation const & location, std::string const & exceptionName, std::vector> const & forallClause, std::vector> const & params, std::vector> const & members ) { ast::StructDecl * decl = new ast::StructDecl( location, exceptionName ); decl->members.push_back( new ast::ObjectDecl( location, "virtual_table", new ast::PointerType( createVTableInstType( exceptionName, params ) ) ) ); for ( ast::ptr const & member : members ) { decl->members.push_back( ast::deepCopy( member ) ); } decl->body = true; for ( ast::ptr const & param : forallClause ) { decl->params.push_back( ast::deepCopy( param ) ); } return decl; } ast::ObjectDecl const * createExternTypeId( CodeLocation const & location, std::string const & exceptionName, std::vector> const & params ) { return new ast::ObjectDecl( location, Virtual::typeIdName( exceptionName ), createVTableInstType( exceptionName, params ), nullptr, ast::Storage::Extern, ast::Linkage::Cforall, nullptr, { new ast::Attribute( "cfa_linkonce" ) } ); } ast::ObjectDecl * createExternVTable( CodeLocation const & location, std::string const & exceptionName, std::vector> const & params, std::string const & tableName ) { return new ast::ObjectDecl( location, tableName, createVTableInstType( exceptionName, params ), nullptr, ast::Storage::Extern, ast::Linkage::Cforall ); } ast::FunctionDecl const * createCopy( CodeLocation const & location, std::string const & exceptionName, std::vector> const & params ) { return new ast::FunctionDecl( location, "copy", {/* forall */}, {/* assertions */}, { new ast::ObjectDecl( location, "this", new ast::PointerType( createExceptionInstType( exceptionName, params ) ) ), new ast::ObjectDecl( location, "that", new ast::PointerType( createExceptionInstType( exceptionName, params ) ) ), }, { new ast::ObjectDecl( location, "", new ast::VoidType() ), }, new ast::CompoundStmt( location, { new ast::ExprStmt( location, new ast::UntypedExpr( location, new ast::NameExpr( location, "?{}" ), { new ast::UntypedExpr( location, new ast::NameExpr( location, "*?" ), { new ast::NameExpr( location, "this" ) } ), new ast::UntypedExpr( location, new ast::NameExpr( location, "*?" ), { new ast::NameExpr( location, "that" ) } ), } ) ), } ), ast::Storage::Classes(), ast::Linkage::Cforall, { new ast::Attribute( "cfa_linkonce" ) } ); } ast::FunctionDecl const * createMsg( CodeLocation const & location, std::string const & exceptionName, std::vector> const & params ) { std::stringstream msg; msg << exceptionName; // The forall variant, add parameters to the string. if ( !params.empty() ) { msg << "("; bool first = true; for ( auto & param : params ) { // Seperator Logic: A comma proceeds all but the first object. if ( first ) { first = false; } else { msg << ", "; } ast::print( msg, param.get() ); } msg << ")"; } return new ast::FunctionDecl( location, "msg", {/* forall */}, {/* assertions */}, { new ast::ObjectDecl( location, "this", new ast::PointerType( createExceptionInstType( exceptionName, params ) ) ), }, { new ast::ObjectDecl( location, "", new ast::PointerType( new ast::BasicType( ast::BasicKind::Char, ast::CV::Const ) ) ), }, new ast::CompoundStmt( location, { new ast::ReturnStmt( location, ast::ConstantExpr::from_string( location, msg.str() ) ), } ), ast::Storage::Classes(), ast::Linkage::Cforall, { new ast::Attribute( "cfa_linkonce" ) } ); } ast::ObjectDecl * createVirtualTable( CodeLocation const & location, std::string const & exceptionName, std::vector> const & params, std::string const & tableName ) { ast::StructInstType * sizeType = new ast::StructInstType( exceptionName ); for ( ast::ptr const & param : params ) { sizeType->params.push_back( ast::deepCopy( param ) ); } std::vector> inits { new ast::SingleInit( location, new ast::AddressExpr( location, new ast::NameExpr( location, Virtual::typeIdName( exceptionName ) ) ) ), new ast::SingleInit( location, new ast::SizeofExpr( location, sizeType ) ), new ast::SingleInit( location, new ast::NameExpr( location, "copy" ) ), new ast::SingleInit( location, new ast::NameExpr( location, "^?{}" ) ), new ast::SingleInit( location, new ast::NameExpr( location, "msg" ) ), }; std::vector> dsigs { new ast::Designation( location, { new ast::NameExpr( location, "__cfavir_typeid" ) } ), new ast::Designation( location, { new ast::NameExpr( location, "size" ) } ), new ast::Designation( location, { new ast::NameExpr( location, "copy" ) } ), new ast::Designation( location, { new ast::NameExpr( location, "^?{}" ) } ), new ast::Designation( location, { new ast::NameExpr( location, "msg" ) } ), }; return new ast::ObjectDecl( location, tableName, createVTableInstType( exceptionName, params ), new ast::ListInit( location, std::move( inits ), std::move( dsigs ) ) ); } struct ExceptDeclCore : public ast::WithDeclsToAdd { ast::StructDecl const * transformExcept( ast::StructDecl const * decl ); ast::ObjectDecl const * transformVTable( ast::ObjectDecl const * decl, ast::VTableType const * type ); ast::StructDecl const * postvisit( ast::StructDecl const * decl ) { // Exceptions don't get their own node type, so filter that. if ( ast::AggregateDecl::Exception == decl->kind ) { return transformExcept( decl ); } return decl; } ast::ObjectDecl const * postvisit( ast::ObjectDecl const * decl ) { // Modify remaining objects that have a vtable type. if ( auto * type = decl->type.as() ) { return transformVTable( decl, type ); } return decl; } }; ast::StructDecl const * ExceptDeclCore::transformExcept( ast::StructDecl const * decl ) { CodeLocation const & location = decl->location; std::string const & exceptionName = decl->name; std::vector> const & forall = decl->params; std::vector> params = forallToParams( forall ); std::vector> const & members = decl->members; declsToAddBefore.push_back( createTypeIdStruct( location, exceptionName, forall ) ); if ( forall.empty() ) { // Non-forall variant. declsToAddBefore.push_back( createTypeIdValue( location, exceptionName, params ) ); } declsToAddBefore.push_back( createExceptionStructForward( location, exceptionName, forall ) ); declsToAddBefore.push_back( createVirtualTableStruct( location, exceptionName, forall, params ) ); return createExceptionStruct( location, exceptionName, forall, params, members ); } ast::ObjectDecl const * ExceptDeclCore::transformVTable( ast::ObjectDecl const * decl, ast::VTableType const * type ) { CodeLocation const & location = decl->location; auto base = type->base.strict_as(); std::string const & exceptionName = base->name; std::vector> const & params = base->params; std::string const & tableName = decl->name; ast::ObjectDecl * retDecl; if ( decl->storage.is_extern ) { // Unique type-ids are only needed for polymorphic instances. if ( !params.empty() ) { declsToAddBefore.push_back( createExternTypeId( location, exceptionName, params ) ); } retDecl = createExternVTable( location, exceptionName, params, tableName ); } else { // Unique type-ids are only needed for polymorphic instances. if ( !params.empty() ) { declsToAddBefore.push_back( createTypeIdValue( location, exceptionName, params ) ); } declsToAddBefore.push_back( createCopy( location, exceptionName, params ) ); declsToAddBefore.push_back( createMsg( location, exceptionName, params ) ); retDecl = createVirtualTable( location, exceptionName, params, tableName ); } for ( ast::ptr const & attr : decl->attributes ) { retDecl->attributes.push_back( attr ); } return retDecl; } struct VTableCore { ast::StructInstType const * postvisit( ast::VTableType const * type ) { auto inst = type->base.as(); std::string vtableName = Virtual::vtableTypeName( inst->name ); auto newType = new ast::StructInstType( vtableName ); for ( ast::ptr const & param : inst->params ) { newType->params.push_back( param ); } return newType; } }; } // namespace void translateExcept( ast::TranslationUnit & translationUnit ) { // Can I combine these? // Second pass really only covers what the first has missed. // Maybe if the first one is all previsits and the second all postvisit. ast::Pass::run( translationUnit ); ast::Pass::run( translationUnit ); } } // namespace ControlStruct // Local Variables: // // tab-width: 4 // // mode: c++ // // compile-command: "make install" // // End: //