- Timestamp:
- May 1, 2023, 4:19:09 PM (2 years ago)
- Branches:
- ADT, ast-experimental, master
- Children:
- c083c3d
- Parents:
- a50fdfb (diff), 985b624 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Location:
- src
- Files:
-
- 6 added
- 45 edited
Legend:
- Unmodified
- Added
- Removed
-
src/AST/Attribute.hpp
ra50fdfb r6e1e2d0 27 27 class Expr; 28 28 29 /// An entry in an attribute list: `__attribute__(( ... ))` 29 30 class Attribute final : public Node { 30 31 public: -
src/AST/Convert.cpp
ra50fdfb r6e1e2d0 559 559 auto stmt = new SuspendStmt(); 560 560 stmt->then = get<CompoundStmt>().accept1( node->then ); 561 switch (node->type) {561 switch (node->kind) { 562 562 case ast::SuspendStmt::None : stmt->type = SuspendStmt::None ; break; 563 563 case ast::SuspendStmt::Coroutine: stmt->type = SuspendStmt::Coroutine; break; … … 1695 1695 GET_ACCEPT_V(attributes, Attribute), 1696 1696 { old->get_funcSpec().val }, 1697 old->type->isVarArgs1697 (old->type->isVarArgs) ? ast::VariableArgs : ast::FixedArgs 1698 1698 }; 1699 1699 … … 2001 2001 GET_ACCEPT_1(else_, Stmt), 2002 2002 GET_ACCEPT_V(initialization, Stmt), 2003 old->isDoWhile,2003 (old->isDoWhile) ? ast::DoWhile : ast::While, 2004 2004 GET_LABELS_V(old->labels) 2005 2005 ); … … 2143 2143 virtual void visit( const SuspendStmt * old ) override final { 2144 2144 if ( inCache( old ) ) return; 2145 ast::SuspendStmt:: Typetype;2145 ast::SuspendStmt::Kind type; 2146 2146 switch (old->type) { 2147 2147 case SuspendStmt::Coroutine: type = ast::SuspendStmt::Coroutine; break; -
src/AST/Decl.cpp
ra50fdfb r6e1e2d0 57 57 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns, 58 58 CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage, 59 std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool isVarArgs)59 std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, ArgumentFlag isVarArgs ) 60 60 : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), 61 61 type_params(std::move(forall)), assertions(), 62 62 params(std::move(params)), returns(std::move(returns)), stmts( stmts ) { 63 FunctionType * ftype = new FunctionType( static_cast<ArgumentFlag>(isVarArgs));63 FunctionType * ftype = new FunctionType( isVarArgs ); 64 64 for (auto & param : this->params) { 65 65 ftype->params.emplace_back(param->get_type()); … … 81 81 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns, 82 82 CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage, 83 std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool isVarArgs)83 std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, ArgumentFlag isVarArgs ) 84 84 : DeclWithType( location, name, storage, linkage, std::move(attrs), fs ), 85 85 type_params( std::move( forall) ), assertions( std::move( assertions ) ), 86 86 params( std::move(params) ), returns( std::move(returns) ), 87 87 type( nullptr ), stmts( stmts ) { 88 FunctionType * type = new FunctionType( (isVarArgs) ? VariableArgs : FixedArgs );88 FunctionType * type = new FunctionType( isVarArgs ); 89 89 for ( auto & param : this->params ) { 90 90 type->params.emplace_back( param->get_type() ); -
src/AST/Decl.hpp
ra50fdfb r6e1e2d0 10 10 // Created On : Thu May 9 10:00:00 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Thu Nov 24 9:44:00 202213 // Update Count : 3 412 // Last Modified On : Wed Apr 5 10:42:00 2023 13 // Update Count : 35 14 14 // 15 15 … … 122 122 }; 123 123 124 /// Function variable arguments flag 125 enum ArgumentFlag { FixedArgs, VariableArgs }; 126 124 127 /// Object declaration `int foo()` 125 128 class FunctionDecl : public DeclWithType { … … 144 147 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns, 145 148 CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::Cforall, 146 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false);149 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, ArgumentFlag isVarArgs = FixedArgs ); 147 150 148 151 FunctionDecl( const CodeLocation & location, const std::string & name, … … 150 153 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns, 151 154 CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::Cforall, 152 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false);155 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, ArgumentFlag isVarArgs = FixedArgs ); 153 156 154 157 const Type * get_type() const override; … … 313 316 public: 314 317 bool isTyped; // isTyped indicated if the enum has a declaration like: 315 // enum (type_optional) Name {...} 318 // enum (type_optional) Name {...} 316 319 ptr<Type> base; // if isTyped == true && base.get() == nullptr, it is a "void" type enum 317 320 enum class EnumHiding { Visible, Hide } hide; … … 371 374 }; 372 375 376 /// Assembly declaration: `asm ... ( "..." : ... )` 373 377 class AsmDecl : public Decl { 374 378 public: -
src/AST/Expr.hpp
ra50fdfb r6e1e2d0 254 254 }; 255 255 256 /// A name qualified by a namespace or type. 256 257 class QualifiedNameExpr final : public Expr { 257 258 public: … … 259 260 std::string name; 260 261 261 QualifiedNameExpr( const CodeLocation & loc, const Decl * d, const std::string & n ) 262 QualifiedNameExpr( const CodeLocation & loc, const Decl * d, const std::string & n ) 262 263 : Expr( loc ), type_decl( d ), name( n ) {} 263 264 … … 621 622 }; 622 623 624 /// A name that refers to a generic dimension parameter. 623 625 class DimensionExpr final : public Expr { 624 626 public: … … 910 912 }; 911 913 912 913 914 } 914 915 -
src/AST/Init.hpp
ra50fdfb r6e1e2d0 117 117 ptr<Init> init; 118 118 119 ConstructorInit( 119 ConstructorInit( 120 120 const CodeLocation & loc, const Stmt * ctor, const Stmt * dtor, const Init * init ) 121 121 : Init( loc, MaybeConstruct ), ctor( ctor ), dtor( dtor ), init( init ) {} -
src/AST/Inspect.cpp
ra50fdfb r6e1e2d0 10 10 // Created On : Fri Jun 24 13:16:31 2022 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Oct 3 11:04:00 202213 // Update Count : 312 // Last Modified On : Fri Apr 14 15:09:00 2023 13 // Update Count : 4 14 14 // 15 15 … … 168 168 } 169 169 170 bool isUnnamedBitfield( const ast::ObjectDecl * obj ) { 171 return obj && obj->name.empty() && obj->bitfieldWidth; 172 } 173 170 174 } // namespace ast -
src/AST/Inspect.hpp
ra50fdfb r6e1e2d0 10 10 // Created On : Fri Jun 24 13:16:31 2022 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Thr Sep 22 13:44:00 202213 // Update Count : 212 // Last Modified On : Fri Apr 14 15:09:00 2023 13 // Update Count : 3 14 14 // 15 15 … … 38 38 const ApplicationExpr * isIntrinsicCallExpr( const Expr * expr ); 39 39 40 /// Returns true if obj's name is the empty string and it has a bitfield width. 41 bool isUnnamedBitfield( const ObjectDecl * obj ); 42 40 43 } -
src/AST/Pass.impl.hpp
ra50fdfb r6e1e2d0 2075 2075 if ( __visit_children() ) { 2076 2076 maybe_accept( node, &TupleType::types ); 2077 maybe_accept( node, &TupleType::members );2078 2077 } 2079 2078 -
src/AST/Print.cpp
ra50fdfb r6e1e2d0 766 766 virtual const ast::Stmt * visit( const ast::SuspendStmt * node ) override final { 767 767 os << "Suspend Statement"; 768 switch (node-> type) {769 770 771 768 switch (node->kind) { 769 case ast::SuspendStmt::None : os << " with implicit target"; break; 770 case ast::SuspendStmt::Generator: os << " for generator"; break; 771 case ast::SuspendStmt::Coroutine: os << " for coroutine"; break; 772 772 } 773 773 os << endl; -
src/AST/Stmt.hpp
ra50fdfb r6e1e2d0 10 10 // Created On : Wed May 8 13:00:00 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed Apr 20 14:34:00 202213 // Update Count : 3 612 // Last Modified On : Wed Apr 5 10:34:00 2023 13 // Update Count : 37 14 14 // 15 15 … … 205 205 }; 206 206 207 // A while loop or a do-while loop: 208 enum WhileDoKind { While, DoWhile }; 209 207 210 // While loop: while (...) ... else ... or do ... while (...) else ...; 208 211 class WhileDoStmt final : public Stmt { … … 212 215 ptr<Stmt> else_; 213 216 std::vector<ptr<Stmt>> inits; 214 boolisDoWhile;217 WhileDoKind isDoWhile; 215 218 216 219 WhileDoStmt( const CodeLocation & loc, const Expr * cond, const Stmt * body, 217 const std::vector<ptr<Stmt>> && inits, bool isDoWhile = false, const std::vector<Label> && labels = {} )220 const std::vector<ptr<Stmt>> && inits, WhileDoKind isDoWhile = While, const std::vector<Label> && labels = {} ) 218 221 : Stmt(loc, std::move(labels)), cond(cond), body(body), else_(nullptr), inits(std::move(inits)), isDoWhile(isDoWhile) {} 219 222 220 223 WhileDoStmt( const CodeLocation & loc, const Expr * cond, const Stmt * body, const Stmt * else_, 221 const std::vector<ptr<Stmt>> && inits, bool isDoWhile = false, const std::vector<Label> && labels = {} )224 const std::vector<ptr<Stmt>> && inits, WhileDoKind isDoWhile = While, const std::vector<Label> && labels = {} ) 222 225 : Stmt(loc, std::move(labels)), cond(cond), body(body), else_(else_), inits(std::move(inits)), isDoWhile(isDoWhile) {} 223 226 … … 364 367 public: 365 368 ptr<CompoundStmt> then; 366 enum Type { None, Coroutine, Generator } type= None;367 368 SuspendStmt( const CodeLocation & loc, const CompoundStmt * then, Type type, const std::vector<Label> && labels = {} )369 : Stmt(loc, std::move(labels)), then(then), type(type) {}369 enum Kind { None, Coroutine, Generator } kind = None; 370 371 SuspendStmt( const CodeLocation & loc, const CompoundStmt * then, Kind kind, const std::vector<Label> && labels = {} ) 372 : Stmt(loc, std::move(labels)), then(then), kind(kind) {} 370 373 371 374 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } … … 424 427 }; 425 428 429 // Clause in a waitfor statement: waitfor (..., ...) ... 426 430 class WaitForClause final : public WhenClause { 427 431 public: … … 527 531 MUTATE_FRIEND 528 532 }; 533 529 534 } // namespace ast 530 535 -
src/AST/SymbolTable.cpp
ra50fdfb r6e1e2d0 260 260 void SymbolTable::addId( const DeclWithType * decl, const Expr * baseExpr ) { 261 261 // default handling of conflicts is to raise an error 262 addId ( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );262 addIdCommon( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr ); 263 263 } 264 264 265 265 void SymbolTable::addDeletedId( const DeclWithType * decl, const Decl * deleter ) { 266 266 // default handling of conflicts is to raise an error 267 addId ( decl, OnConflict::error(), nullptr, deleter );267 addIdCommon( decl, OnConflict::error(), nullptr, deleter ); 268 268 } 269 269 … … 677 677 } 678 678 679 void SymbolTable::addId (680 const DeclWithType * decl, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr,681 const Decl * deleter ) {679 void SymbolTable::addIdCommon( 680 const DeclWithType * decl, SymbolTable::OnConflict handleConflicts, 681 const Expr * baseExpr, const Decl * deleter ) { 682 682 SpecialFunctionKind kind = getSpecialFunctionKind(decl->name); 683 683 if (kind == NUMBER_OF_KINDS) { // not a special decl 684 addId (decl, decl->name, idTable, handleConflicts, baseExpr, deleter);684 addIdToTable(decl, decl->name, idTable, handleConflicts, baseExpr, deleter); 685 685 } 686 686 else { … … 695 695 assertf(false, "special decl with non-function type"); 696 696 } 697 addId(decl, key, specialFunctionTable[kind], handleConflicts, baseExpr, deleter); 698 } 699 } 700 701 void SymbolTable::addId( 702 const DeclWithType * decl, const std::string & lookupKey, IdTable::Ptr & table, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr, 703 const Decl * deleter ) { 697 addIdToTable(decl, key, specialFunctionTable[kind], handleConflicts, baseExpr, deleter); 698 } 699 } 700 701 void SymbolTable::addIdToTable( 702 const DeclWithType * decl, const std::string & lookupKey, 703 IdTable::Ptr & table, SymbolTable::OnConflict handleConflicts, 704 const Expr * baseExpr, const Decl * deleter ) { 704 705 ++*stats().add_calls; 705 706 const std::string &name = decl->name; … … 778 779 void SymbolTable::addMembers( 779 780 const AggregateDecl * aggr, const Expr * expr, SymbolTable::OnConflict handleConflicts ) { 780 for ( const Decl *decl : aggr->members ) {781 if ( auto dwt = dynamic_cast< const DeclWithType * >( decl ) ) {782 addId( dwt, handleConflicts, expr );783 if ( dwt->name == "" ) {784 const Type * t = dwt->get_type()->stripReferences();785 if ( auto rty = dynamic_cast<const BaseInstType *>( t ) ) {786 if ( ! dynamic_cast<const StructInstType *>(rty)787 && ! dynamic_cast<const UnionInstType *>(rty) ) continue;788 ResolvExpr::Cost cost = ResolvExpr::Cost::zero;789 ast::ptr<ast::TypeSubstitution> tmp = expr->env;790 expr = mutate_field(expr, &Expr::env, nullptr);791 const Expr * base = ResolvExpr::referenceToRvalueConversion( expr, cost );792 base = mutate_field(base, &Expr::env, tmp);793 794 addMembers(795 rty->aggr(), new MemberExpr{ base->location, dwt, base }, handleConflicts ); 796 }797 }781 for ( const ptr<Decl> & decl : aggr->members ) { 782 auto dwt = decl.as<DeclWithType>(); 783 if ( nullptr == dwt ) continue; 784 addIdCommon( dwt, handleConflicts, expr ); 785 // Inline through unnamed struct/union members. 786 if ( "" != dwt->name ) continue; 787 const Type * t = dwt->get_type()->stripReferences(); 788 if ( auto rty = dynamic_cast<const BaseInstType *>( t ) ) { 789 if ( ! dynamic_cast<const StructInstType *>(rty) 790 && ! dynamic_cast<const UnionInstType *>(rty) ) continue; 791 ResolvExpr::Cost cost = ResolvExpr::Cost::zero; 792 ast::ptr<ast::TypeSubstitution> tmp = expr->env; 793 expr = mutate_field(expr, &Expr::env, nullptr); 794 const Expr * base = ResolvExpr::referenceToRvalueConversion( expr, cost ); 795 base = mutate_field(base, &Expr::env, tmp); 796 797 addMembers( 798 rty->aggr(), new MemberExpr{ base->location, dwt, base }, handleConflicts ); 798 799 } 799 800 } -
src/AST/SymbolTable.hpp
ra50fdfb r6e1e2d0 192 192 193 193 /// common code for addId, addDeletedId, etc. 194 void addId (195 const DeclWithType * decl, OnConflict handleConflicts, const Expr * baseExpr = nullptr,196 const Decl * deleter = nullptr );194 void addIdCommon( 195 const DeclWithType * decl, OnConflict handleConflicts, 196 const Expr * baseExpr = nullptr, const Decl * deleter = nullptr ); 197 197 198 198 /// common code for addId when special decls are placed into separate tables 199 void addId( 200 const DeclWithType * decl, const std::string & lookupKey, IdTable::Ptr & idTable, OnConflict handleConflicts, 199 void addIdToTable( 200 const DeclWithType * decl, const std::string & lookupKey, 201 IdTable::Ptr & idTable, OnConflict handleConflicts, 201 202 const Expr * baseExpr = nullptr, const Decl * deleter = nullptr); 202 203 203 204 /// adds all of the members of the Aggregate (addWith helper) 204 205 void addMembers( const AggregateDecl * aggr, const Expr * expr, OnConflict handleConflicts ); -
src/AST/Type.cpp
ra50fdfb r6e1e2d0 10 10 // Created On : Mon May 13 15:00:00 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Thu Nov 24 9:49:00 202213 // Update Count : 612 // Last Modified On : Thu Apr 6 15:59:00 2023 13 // Update Count : 7 14 14 // 15 15 … … 199 199 200 200 TupleType::TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q ) 201 : Type( q ), types( std::move(ts) ), members() { 202 // This constructor is awkward. `TupleType` needs to contain objects so that members can be 203 // named, but members without initializer nodes end up getting constructors, which breaks 204 // things. This happens because the object decls have to be visited so that their types are 205 // kept in sync with the types listed here. Ultimately, the types listed here should perhaps 206 // be eliminated and replaced with a list-view over members. The temporary solution is to 207 // make a `ListInit` with `maybeConstructed = false`, so when the object is visited it is not 208 // constructed. Potential better solutions include: 209 // a) Separate `TupleType` from its declarations, into `TupleDecl` and `Tuple{Inst?}Type`, 210 // similar to the aggregate types. 211 // b) Separate initializer nodes better, e.g. add a `MaybeConstructed` node that is replaced 212 // by `genInit`, rather than the current boolean flag. 213 members.reserve( types.size() ); 214 for ( const Type * ty : types ) { 215 members.emplace_back( new ObjectDecl{ 216 CodeLocation(), "", ty, new ListInit( CodeLocation(), {}, {}, NoConstruct ), 217 Storage::Classes{}, Linkage::Cforall } ); 218 } 219 } 201 : Type( q ), types( std::move(ts) ) {} 220 202 221 203 bool isUnboundType(const Type * type) { -
src/AST/Type.hpp
ra50fdfb r6e1e2d0 10 10 // Created On : Thu May 9 10:00:00 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Thu Nov 24 9:47:00 202213 // Update Count : 812 // Last Modified On : Thu Apr 6 15:58:00 2023 13 // Update Count : 9 14 14 // 15 15 … … 265 265 }; 266 266 267 /// Function variable arguments flag268 enum ArgumentFlag { FixedArgs, VariableArgs };269 270 267 /// Type of a function `[R1, R2](*)(P1, P2, P3)` 271 268 class FunctionType final : public Type { … … 460 457 public: 461 458 std::vector<ptr<Type>> types; 462 std::vector<ptr<Decl>> members;463 459 464 460 TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q = {} ); -
src/Common/CodeLocationTools.cpp
ra50fdfb r6e1e2d0 210 210 211 211 struct LeafKindVisitor : public ast::Visitor { 212 LeafKind kind;212 LeafKind result; 213 213 214 214 #define VISIT(node_type, return_type) \ 215 215 const ast::return_type * visit( const ast::node_type * ) final { \ 216 kind= LeafKind::node_type; \216 result = LeafKind::node_type; \ 217 217 return nullptr; \ 218 218 } … … 224 224 225 225 LeafKind get_leaf_kind( ast::Node const * node ) { 226 LeafKindVisitor visitor; 227 node->accept( visitor ); 228 return visitor.kind; 226 return ast::Pass<LeafKindVisitor>::read( node ); 229 227 } 230 228 -
src/Common/Iterate.hpp
ra50fdfb r6e1e2d0 20 20 #include <iterator> 21 21 22 // it's nice to actually be able to increment iterators by an arbitrary amount22 // Returns an iterator that is it advanced n times. 23 23 template< class InputIt, class Distance > 24 24 InputIt operator+( InputIt it, Distance n ) { … … 50 50 51 51 // ----------------------------------------------------------------------------- 52 // Helper struct and function to support 53 // for ( val_and_index : enumerate( container ) ) {} 54 // which iterates through the container and tracks the index as well. 55 52 56 template< typename T > 53 57 struct enumerate_t { … … 109 113 110 114 // ----------------------------------------------------------------------------- 115 // Helper function to transform one iterable container into another. 116 111 117 template< typename OutType, typename Range, typename Functor > 112 118 OutType map_range( const Range& range, Functor&& functor ) { … … 206 212 // Helper struct and function to support 207 213 // for ( val : lazy_map( container1, f ) ) {} 208 // syntax to have a for each that iterates a container, mapping each element by applying f 214 // syntax to have a for each that iterates a container, 215 // mapping each element by applying f. 216 209 217 template< typename T, typename Func > 210 218 struct lambda_iterate_t { -
src/CompilationState.cc
ra50fdfb r6e1e2d0 9 9 // Author : Rob Schluntz 10 10 // Created On : Mon Ju1 30 10:47:01 2018 11 // Last Modified By : Henry Xue12 // Last Modified On : Tue Jul 20 04:27:35 202113 // Update Count : 511 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 10 19:12:50 2023 13 // Update Count : 6 14 14 // 15 15 … … 27 27 expraltp = false, 28 28 genericsp = false, 29 invariant = false, 29 30 libcfap = false, 30 31 nopreludep = false, -
src/CompilationState.h
ra50fdfb r6e1e2d0 9 9 // Author : Rob Schluntz 10 10 // Created On : Mon Ju1 30 10:47:01 2018 11 // Last Modified By : Henry Xue12 // Last Modified On : Tue Jul 20 04:27:35 202113 // Update Count : 511 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 10 19:12:53 2023 13 // Update Count : 6 14 14 // 15 15 … … 26 26 expraltp, 27 27 genericsp, 28 invariant, 28 29 libcfap, 29 30 nopreludep, -
src/Concurrency/KeywordsNew.cpp
ra50fdfb r6e1e2d0 779 779 780 780 const ast::Stmt * SuspendKeyword::postvisit( const ast::SuspendStmt * stmt ) { 781 switch ( stmt-> type) {781 switch ( stmt->kind ) { 782 782 case ast::SuspendStmt::None: 783 783 // Use the context to determain the implicit target. -
src/InitTweak/FixInitNew.cpp
ra50fdfb r6e1e2d0 14 14 #include <utility> // for pair 15 15 16 #include "AST/DeclReplacer.hpp" 17 #include "AST/Expr.hpp" 16 18 #include "AST/Inspect.hpp" // for getFunction, getPointerBase, g... 19 #include "AST/Node.hpp" 20 #include "AST/Pass.hpp" 21 #include "AST/Print.hpp" 22 #include "AST/SymbolTable.hpp" 23 #include "AST/Type.hpp" 17 24 #include "CodeGen/GenType.h" // for genPrettyType 18 25 #include "CodeGen/OperatorTable.h" 19 #include "Common/CodeLocationTools.hpp"20 26 #include "Common/PassVisitor.h" // for PassVisitor, WithStmtsToAdd 21 27 #include "Common/SemanticError.h" // for SemanticError … … 28 34 #include "ResolvExpr/Unify.h" // for typesCompatible 29 35 #include "SymTab/Autogen.h" // for genImplicitCall 36 #include "SymTab/GenImplicitCall.hpp" // for genImplicitCall 30 37 #include "SymTab/Indexer.h" // for Indexer 31 38 #include "SymTab/Mangler.h" // for Mangler … … 45 52 #include "Validate/FindSpecialDecls.h" // for dtorStmt, dtorStructDestroy 46 53 47 #include "AST/Expr.hpp"48 #include "AST/Node.hpp"49 #include "AST/Pass.hpp"50 #include "AST/Print.hpp"51 #include "AST/SymbolTable.hpp"52 #include "AST/Type.hpp"53 #include "AST/DeclReplacer.hpp"54 55 54 extern bool ctordtorp; // print all debug 56 55 extern bool ctorp; // print ctor debug … … 63 62 namespace InitTweak { 64 63 namespace { 64 65 // Shallow copy the pointer list for return. 66 std::vector<ast::ptr<ast::TypeDecl>> getGenericParams( const ast::Type * t ) { 67 if ( auto inst = dynamic_cast<const ast::StructInstType *>( t ) ) { 68 return inst->base->params; 69 } 70 if ( auto inst = dynamic_cast<const ast::UnionInstType *>( t ) ) { 71 return inst->base->params; 72 } 73 return {}; 74 } 75 76 /// Given type T, generate type of default ctor/dtor, i.e. function type void (*) (T &). 77 ast::FunctionDecl * genDefaultFunc( 78 const CodeLocation loc, 79 const std::string fname, 80 const ast::Type * paramType, 81 bool maybePolymorphic = true) { 82 std::vector<ast::ptr<ast::TypeDecl>> typeParams; 83 if ( maybePolymorphic ) typeParams = getGenericParams( paramType ); 84 auto dstParam = new ast::ObjectDecl( loc, 85 "_dst", 86 new ast::ReferenceType( paramType ), 87 nullptr, 88 {}, 89 ast::Linkage::Cforall 90 ); 91 return new ast::FunctionDecl( loc, 92 fname, 93 std::move(typeParams), 94 {dstParam}, 95 {}, 96 new ast::CompoundStmt(loc), 97 {}, 98 ast::Linkage::Cforall 99 ); 100 } 101 65 102 struct SelfAssignChecker { 66 103 void previsit( const ast::ApplicationExpr * appExpr ); … … 121 158 void previsit( const ast::FunctionDecl * ) { visit_children = false; } 122 159 123 160 protected: 124 161 ObjectSet curVars; 125 162 }; … … 202 239 203 240 SemanticErrorException errors; 204 241 private: 205 242 template< typename... Params > 206 243 void emit( CodeLocation, const Params &... params ); … … 288 325 static UniqueName dtorNamer( "__cleanup_dtor" ); 289 326 std::string name = dtorNamer.newName(); 290 ast::FunctionDecl * dtorFunc = SymTab::genDefaultFunc( loc, name, objDecl->type->stripReferences(), false );327 ast::FunctionDecl * dtorFunc = genDefaultFunc( loc, name, objDecl->type->stripReferences(), false ); 291 328 stmtsToAdd.push_back( new ast::DeclStmt(loc, dtorFunc ) ); 292 329 … … 1080 1117 void InsertDtors::previsit( const ast::BranchStmt * stmt ) { 1081 1118 switch( stmt->kind ) { 1082 1083 1119 case ast::BranchStmt::Continue: 1120 case ast::BranchStmt::Break: 1084 1121 // could optimize the break/continue case, because the S_L-S_G check is unnecessary (this set should 1085 1122 // always be empty), but it serves as a small sanity check. 1086 1123 case ast::BranchStmt::Goto: 1087 1124 handleGoto( stmt ); 1088 1125 break; 1089 1126 default: 1090 1127 assert( false ); 1091 1128 } // switch … … 1312 1349 // xxx - functions returning ast::ptr seems wrong... 1313 1350 auto res = ResolvExpr::findVoidExpression( untypedExpr, { symtab, transUnit().global } ); 1314 // Fix CodeLocation (at least until resolver is fixed). 1315 auto fix = localFillCodeLocations( untypedExpr->location, res.release() ); 1316 return strict_dynamic_cast<const ast::Expr *>( fix ); 1351 return res.release(); 1317 1352 } 1318 1353 -
src/InitTweak/GenInit.cc
ra50fdfb r6e1e2d0 39 39 #include "ResolvExpr/Resolver.h" 40 40 #include "SymTab/Autogen.h" // for genImplicitCall 41 #include "SymTab/GenImplicitCall.hpp" // for genImplicitCall 41 42 #include "SymTab/Mangler.h" // for Mangler 42 43 #include "SynTree/LinkageSpec.h" // for isOverridable, C -
src/Parser/DeclarationNode.cc
ra50fdfb r6e1e2d0 10 10 // Created On : Sat May 16 12:34:05 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T ue Apr 4 10:28:00 202313 // Update Count : 139 212 // Last Modified On : Thr Apr 20 11:46:00 2023 13 // Update Count : 1393 14 14 // 15 16 #include "DeclarationNode.h" 15 17 16 18 #include <cassert> // for assert, assertf, strict_dynamic_cast … … 34 36 #include "Common/UniqueName.h" // for UniqueName 35 37 #include "Common/utility.h" // for maybeClone 36 #include "Parser/ParseNode.h" // for DeclarationNode, ExpressionNode 38 #include "Parser/ExpressionNode.h" // for ExpressionNode 39 #include "Parser/InitializerNode.h"// for InitializerNode 40 #include "Parser/StatementNode.h" // for StatementNode 37 41 #include "TypeData.h" // for TypeData, TypeData::Aggregate_t 38 42 #include "TypedefTable.h" // for TypedefTable … … 999 1003 } 1000 1004 1001 void buildList( const DeclarationNode * firstNode, 1005 // If a typedef wraps an anonymous declaration, name the inner declaration 1006 // so it has a consistent name across translation units. 1007 static void nameTypedefedDecl( 1008 DeclarationNode * innerDecl, 1009 const DeclarationNode * outerDecl ) { 1010 TypeData * outer = outerDecl->type; 1011 assert( outer ); 1012 // First make sure this is a typedef: 1013 if ( outer->kind != TypeData::Symbolic || !outer->symbolic.isTypedef ) { 1014 return; 1015 } 1016 TypeData * inner = innerDecl->type; 1017 assert( inner ); 1018 // Always clear any CVs associated with the aggregate: 1019 inner->qualifiers.reset(); 1020 // Handle anonymous aggregates: typedef struct { int i; } foo 1021 if ( inner->kind == TypeData::Aggregate && inner->aggregate.anon ) { 1022 delete inner->aggregate.name; 1023 inner->aggregate.name = new string( "__anonymous_" + *outerDecl->name ); 1024 inner->aggregate.anon = false; 1025 assert( outer->base ); 1026 delete outer->base->aggInst.aggregate->aggregate.name; 1027 outer->base->aggInst.aggregate->aggregate.name = new string( "__anonymous_" + *outerDecl->name ); 1028 outer->base->aggInst.aggregate->aggregate.anon = false; 1029 outer->base->aggInst.aggregate->qualifiers.reset(); 1030 // Handle anonymous enumeration: typedef enum { A, B, C } foo 1031 } else if ( inner->kind == TypeData::Enum && inner->enumeration.anon ) { 1032 delete inner->enumeration.name; 1033 inner->enumeration.name = new string( "__anonymous_" + *outerDecl->name ); 1034 inner->enumeration.anon = false; 1035 assert( outer->base ); 1036 delete outer->base->aggInst.aggregate->enumeration.name; 1037 outer->base->aggInst.aggregate->enumeration.name = new string( "__anonymous_" + *outerDecl->name ); 1038 outer->base->aggInst.aggregate->enumeration.anon = false; 1039 // No qualifiers.reset() here. 1040 } 1041 } 1042 1043 // This code handles a special issue with the attribute transparent_union. 1044 // 1045 // typedef union U { int i; } typedef_name __attribute__(( aligned(16) )) __attribute__(( transparent_union )) 1046 // 1047 // Here the attribute aligned goes with the typedef_name, so variables declared of this type are 1048 // aligned. However, the attribute transparent_union must be moved from the typedef_name to 1049 // alias union U. Currently, this is the only know attribute that must be moved from typedef to 1050 // alias. 1051 static void moveUnionAttribute( ast::Decl * decl, ast::UnionDecl * unionDecl ) { 1052 if ( auto typedefDecl = dynamic_cast<ast::TypedefDecl *>( decl ) ) { 1053 // Is the typedef alias a union aggregate? 1054 if ( nullptr == unionDecl ) return; 1055 1056 // If typedef is an alias for a union, then its alias type was hoisted above and remembered. 1057 if ( auto unionInstType = typedefDecl->base.as<ast::UnionInstType>() ) { 1058 auto instType = ast::mutate( unionInstType ); 1059 // Remove all transparent_union attributes from typedef and move to alias union. 1060 for ( auto attr = instType->attributes.begin() ; attr != instType->attributes.end() ; ) { 1061 assert( *attr ); 1062 if ( (*attr)->name == "transparent_union" || (*attr)->name == "__transparent_union__" ) { 1063 unionDecl->attributes.emplace_back( attr->release() ); 1064 attr = instType->attributes.erase( attr ); 1065 } else { 1066 attr++; 1067 } 1068 } 1069 typedefDecl->base = instType; 1070 } 1071 } 1072 } 1073 1074 // Get the non-anonymous name of the instance type of the declaration, 1075 // if one exists. 1076 static const std::string * getInstTypeOfName( ast::Decl * decl ) { 1077 if ( auto dwt = dynamic_cast<ast::DeclWithType *>( decl ) ) { 1078 if ( auto aggr = dynamic_cast<ast::BaseInstType const *>( dwt->get_type() ) ) { 1079 if ( aggr->name.find("anonymous") == std::string::npos ) { 1080 return &aggr->name; 1081 } 1082 } 1083 } 1084 return nullptr; 1085 } 1086 1087 void buildList( DeclarationNode * firstNode, 1002 1088 std::vector<ast::ptr<ast::Decl>> & outputList ) { 1003 1089 SemanticErrorException errors; 1004 1090 std::back_insert_iterator<std::vector<ast::ptr<ast::Decl>>> out( outputList ); 1005 1091 1006 for ( const DeclarationNode * cur = firstNode ; cur; cur = dynamic_cast< DeclarationNode * >( cur->get_next()) ) {1092 for ( const DeclarationNode * cur = firstNode ; cur ; cur = strict_next( cur ) ) { 1007 1093 try { 1008 bool extracted = false, anon= false;1009 ast:: AggregateDecl * unionDecl = nullptr;1094 bool extracted_named = false; 1095 ast::UnionDecl * unionDecl = nullptr; 1010 1096 1011 1097 if ( DeclarationNode * extr = cur->extractAggregate() ) { 1012 // Handle the case where a SUE declaration is contained within an object or type declaration.1013 1014 1098 assert( cur->type ); 1015 // Replace anonymous SUE name with typedef name to prevent anonymous naming problems across translation units. 1016 if ( cur->type->kind == TypeData::Symbolic && cur->type->symbolic.isTypedef ) { 1017 assert( extr->type ); 1018 // Handle anonymous aggregates: typedef struct { int i; } foo 1019 extr->type->qualifiers.reset(); // clear any CVs associated with the aggregate 1020 if ( extr->type->kind == TypeData::Aggregate && extr->type->aggregate.anon ) { 1021 delete extr->type->aggregate.name; 1022 extr->type->aggregate.name = new string( "__anonymous_" + *cur->name ); 1023 extr->type->aggregate.anon = false; 1024 assert( cur->type->base ); 1025 if ( cur->type->base ) { 1026 delete cur->type->base->aggInst.aggregate->aggregate.name; 1027 cur->type->base->aggInst.aggregate->aggregate.name = new string( "__anonymous_" + *cur->name ); 1028 cur->type->base->aggInst.aggregate->aggregate.anon = false; 1029 cur->type->base->aggInst.aggregate->qualifiers.reset(); 1030 } // if 1031 } // if 1032 // Handle anonymous enumeration: typedef enum { A, B, C } foo 1033 if ( extr->type->kind == TypeData::Enum && extr->type->enumeration.anon ) { 1034 delete extr->type->enumeration.name; 1035 extr->type->enumeration.name = new string( "__anonymous_" + *cur->name ); 1036 extr->type->enumeration.anon = false; 1037 assert( cur->type->base ); 1038 if ( cur->type->base ) { 1039 delete cur->type->base->aggInst.aggregate->enumeration.name; 1040 cur->type->base->aggInst.aggregate->enumeration.name = new string( "__anonymous_" + *cur->name ); 1041 cur->type->base->aggInst.aggregate->enumeration.anon = false; 1042 } // if 1043 } // if 1044 } // if 1045 1046 ast::Decl * decl = extr->build(); 1047 if ( decl ) { 1099 nameTypedefedDecl( extr, cur ); 1100 1101 if ( ast::Decl * decl = extr->build() ) { 1048 1102 // Remember the declaration if it is a union aggregate ? 1049 1103 unionDecl = dynamic_cast<ast::UnionDecl *>( decl ); 1050 1104 1051 decl->location = cur->location;1052 1105 *out++ = decl; 1053 1106 1054 1107 // need to remember the cases where a declaration contains an anonymous aggregate definition 1055 extracted = true;1056 1108 assert( extr->type ); 1057 1109 if ( extr->type->kind == TypeData::Aggregate ) { 1058 1110 // typedef struct { int A } B is the only case? 1059 anon =extr->type->aggregate.anon;1111 extracted_named = !extr->type->aggregate.anon; 1060 1112 } else if ( extr->type->kind == TypeData::Enum ) { 1061 1113 // typedef enum { A } B is the only case? 1062 anon = extr->type->enumeration.anon; 1114 extracted_named = !extr->type->enumeration.anon; 1115 } else { 1116 extracted_named = true; 1063 1117 } 1064 1118 } // if … … 1066 1120 } // if 1067 1121 1068 ast::Decl * decl = cur->build(); 1069 if ( decl ) { 1070 if ( auto typedefDecl = dynamic_cast<ast::TypedefDecl *>( decl ) ) { 1071 if ( unionDecl ) { // is the typedef alias a union aggregate ? 1072 // This code handles a special issue with the attribute transparent_union. 1073 // 1074 // typedef union U { int i; } typedef_name __attribute__(( aligned(16) )) __attribute__(( transparent_union )) 1075 // 1076 // Here the attribute aligned goes with the typedef_name, so variables declared of this type are 1077 // aligned. However, the attribute transparent_union must be moved from the typedef_name to 1078 // alias union U. Currently, this is the only know attribute that must be moved from typedef to 1079 // alias. 1080 1081 // If typedef is an alias for a union, then its alias type was hoisted above and remembered. 1082 if ( auto unionInstType = typedefDecl->base.as<ast::UnionInstType>() ) { 1083 auto instType = ast::mutate( unionInstType ); 1084 // Remove all transparent_union attributes from typedef and move to alias union. 1085 for ( auto attr = instType->attributes.begin() ; attr != instType->attributes.end() ; ) { // forward order 1086 assert( *attr ); 1087 if ( (*attr)->name == "transparent_union" || (*attr)->name == "__transparent_union__" ) { 1088 unionDecl->attributes.emplace_back( attr->release() ); 1089 attr = instType->attributes.erase( attr ); 1090 } else { 1091 attr++; 1092 } // if 1093 } // for 1094 typedefDecl->base = instType; 1095 } // if 1096 } // if 1122 if ( ast::Decl * decl = cur->build() ) { 1123 moveUnionAttribute( decl, unionDecl ); 1124 1125 if ( "" == decl->name && !cur->get_inLine() ) { 1126 // Don't include anonymous declaration for named aggregates, 1127 // but do include them for anonymous aggregates, e.g.: 1128 // struct S { 1129 // struct T { int x; }; // no anonymous member 1130 // struct { int y; }; // anonymous member 1131 // struct T; // anonymous member 1132 // }; 1133 if ( extracted_named ) { 1134 continue; 1135 } 1136 1137 if ( auto name = getInstTypeOfName( decl ) ) { 1138 // Temporary: warn about anonymous member declarations of named types, since 1139 // this conflicts with the syntax for the forward declaration of an anonymous type. 1140 SemanticWarning( cur->location, Warning::AggrForwardDecl, name->c_str() ); 1141 } 1097 1142 } // if 1098 1099 // don't include anonymous declaration for named aggregates, but do include them for anonymous aggregates, e.g.: 1100 // struct S { 1101 // struct T { int x; }; // no anonymous member 1102 // struct { int y; }; // anonymous member 1103 // struct T; // anonymous member 1104 // }; 1105 if ( ! (extracted && decl->name == "" && ! anon && ! cur->get_inLine()) ) { 1106 if ( decl->name == "" ) { 1107 if ( auto dwt = dynamic_cast<ast::DeclWithType *>( decl ) ) { 1108 if ( auto aggr = dynamic_cast<ast::BaseInstType const *>( dwt->get_type() ) ) { 1109 if ( aggr->name.find("anonymous") == std::string::npos ) { 1110 if ( ! cur->get_inLine() ) { 1111 // temporary: warn about anonymous member declarations of named types, since 1112 // this conflicts with the syntax for the forward declaration of an anonymous type 1113 SemanticWarning( cur->location, Warning::AggrForwardDecl, aggr->name.c_str() ); 1114 } // if 1115 } // if 1116 } // if 1117 } // if 1118 } // if 1119 decl->location = cur->location; 1120 *out++ = decl; 1121 } // if 1143 *out++ = decl; 1122 1144 } // if 1123 } catch ( SemanticErrorException & e ) {1145 } catch ( SemanticErrorException & e ) { 1124 1146 errors.append( e ); 1125 1147 } // try … … 1132 1154 1133 1155 // currently only builds assertions, function parameters, and return values 1134 void buildList( constDeclarationNode * firstNode, std::vector<ast::ptr<ast::DeclWithType>> & outputList ) {1156 void buildList( DeclarationNode * firstNode, std::vector<ast::ptr<ast::DeclWithType>> & outputList ) { 1135 1157 SemanticErrorException errors; 1136 1158 std::back_insert_iterator<std::vector<ast::ptr<ast::DeclWithType>>> out( outputList ); 1137 1159 1138 for ( const DeclarationNode * cur = firstNode; cur; cur = dynamic_cast< DeclarationNode * >( cur->get_next()) ) {1160 for ( const DeclarationNode * cur = firstNode; cur; cur = strict_next( cur ) ) { 1139 1161 try { 1140 1162 ast::Decl * decl = cur->build(); 1141 assert ( decl);1163 assertf( decl, "buildList: build for ast::DeclWithType." ); 1142 1164 if ( ast::DeclWithType * dwt = dynamic_cast<ast::DeclWithType *>( decl ) ) { 1143 1165 dwt->location = cur->location; … … 1168 1190 ); 1169 1191 *out++ = obj; 1192 } else { 1193 assertf( false, "buildList: Could not convert to ast::DeclWithType." ); 1170 1194 } // if 1171 } catch ( SemanticErrorException & e ) {1195 } catch ( SemanticErrorException & e ) { 1172 1196 errors.append( e ); 1173 1197 } // try … … 1183 1207 SemanticErrorException errors; 1184 1208 std::back_insert_iterator<std::vector<ast::ptr<ast::Type>>> out( outputList ); 1185 const DeclarationNode * cur = firstNode; 1186 1187 while ( cur ) { 1209 1210 for ( const DeclarationNode * cur = firstNode ; cur ; cur = strict_next( cur ) ) { 1188 1211 try { 1189 1212 * out++ = cur->buildType(); 1190 } catch ( SemanticErrorException & e ) {1213 } catch ( SemanticErrorException & e ) { 1191 1214 errors.append( e ); 1192 1215 } // try 1193 cur = dynamic_cast< DeclarationNode * >( cur->get_next() ); 1194 } // while 1216 } // for 1195 1217 1196 1218 if ( ! errors.isEmpty() ) { -
src/Parser/ExpressionNode.cc
ra50fdfb r6e1e2d0 13 13 // Update Count : 1083 14 14 // 15 16 #include "ExpressionNode.h" 15 17 16 18 #include <cassert> // for assert … … 25 27 #include "Common/SemanticError.h" // for SemanticError 26 28 #include "Common/utility.h" // for maybeMoveBuild, maybeBuild, CodeLo... 27 #include "ParseNode.h" // for ExpressionNode, maybeMoveBuildType 29 #include "DeclarationNode.h" // for DeclarationNode 30 #include "InitializerNode.h" // for InitializerNode 28 31 #include "parserutility.h" // for notZeroExpr 29 32 … … 699 702 } // build_binary_val 700 703 701 ast::Expr * build_binary_ptr( const CodeLocation & location,702 OperKinds op,703 ExpressionNode * expr_node1,704 ExpressionNode * expr_node2 ) {705 return build_binary_val( location, op, expr_node1, expr_node2 );706 } // build_binary_ptr707 708 704 ast::Expr * build_cond( const CodeLocation & location, 709 705 ExpressionNode * expr_node1, -
src/Parser/InitializerNode.cc
ra50fdfb r6e1e2d0 14 14 // 15 15 16 #include "InitializerNode.h" 17 16 18 #include <iostream> // for operator<<, ostream, basic_ostream 17 19 #include <list> // for list 18 20 #include <string> // for operator<<, string 19 20 using namespace std;21 21 22 22 #include "AST/Expr.hpp" // for Expr … … 24 24 #include "Common/SemanticError.h" // for SemanticError 25 25 #include "Common/utility.h" // for maybeBuild 26 #include "ParseNode.h" // for InitializerNode, ExpressionNode 26 #include "ExpressionNode.h" // for ExpressionNode 27 #include "DeclarationNode.h" // for buildList 28 29 using namespace std; 27 30 28 31 static ast::ConstructFlag toConstructFlag( bool maybeConstructed ) { -
src/Parser/ParseNode.h
ra50fdfb r6e1e2d0 38 38 class DeclarationWithType; 39 39 class Initializer; 40 class InitializerNode; 40 41 class ExpressionNode; 41 42 struct StatementNode; … … 80 81 }; // ParseNode 81 82 82 //##############################################################################83 84 class InitializerNode : public ParseNode {85 public:86 InitializerNode( ExpressionNode *, bool aggrp = false, ExpressionNode * des = nullptr );87 InitializerNode( InitializerNode *, bool aggrp = false, ExpressionNode * des = nullptr );88 InitializerNode( bool isDelete );89 ~InitializerNode();90 virtual InitializerNode * clone() const { assert( false ); return nullptr; }91 92 ExpressionNode * get_expression() const { return expr; }93 94 InitializerNode * set_designators( ExpressionNode * des ) { designator = des; return this; }95 ExpressionNode * get_designators() const { return designator; }96 97 InitializerNode * set_maybeConstructed( bool value ) { maybeConstructed = value; return this; }98 bool get_maybeConstructed() const { return maybeConstructed; }99 100 bool get_isDelete() const { return isDelete; }101 102 InitializerNode * next_init() const { return kids; }103 104 void print( std::ostream & os, int indent = 0 ) const;105 void printOneLine( std::ostream & ) const;106 107 virtual ast::Init * build() const;108 private:109 ExpressionNode * expr;110 bool aggregate;111 ExpressionNode * designator; // may be list112 InitializerNode * kids;113 bool maybeConstructed;114 bool isDelete;115 }; // InitializerNode116 117 //##############################################################################118 119 class ExpressionNode final : public ParseNode {120 public:121 ExpressionNode( ast::Expr * expr = nullptr ) : expr( expr ) {}122 virtual ~ExpressionNode() {}123 virtual ExpressionNode * clone() const override {124 if ( nullptr == expr ) return nullptr;125 return static_cast<ExpressionNode*>(126 (new ExpressionNode( ast::shallowCopy( expr.get() ) ))->set_next( maybeCopy( get_next() ) ));127 }128 129 bool get_extension() const { return extension; }130 ExpressionNode * set_extension( bool exten ) { extension = exten; return this; }131 132 virtual void print( std::ostream & os, __attribute__((unused)) int indent = 0 ) const override {133 os << expr.get();134 }135 void printOneLine( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const {}136 137 template<typename T>138 bool isExpressionType() const { return nullptr != dynamic_cast<T>(expr.get()); }139 140 ast::Expr * build() const {141 ast::Expr * node = const_cast<ExpressionNode *>(this)->expr.release();142 node->set_extension( this->get_extension() );143 node->location = this->location;144 return node;145 }146 147 // Public because of lifetime implications (what lifetime implications?)148 std::unique_ptr<ast::Expr> expr;149 private:150 bool extension = false;151 }; // ExpressionNode152 153 83 // Must harmonize with OperName. 154 84 enum class OperKinds { … … 169 99 }; 170 100 171 // These 4 routines modify the string:172 ast::Expr * build_constantInteger( const CodeLocation &, std::string & );173 ast::Expr * build_constantFloat( const CodeLocation &, std::string & );174 ast::Expr * build_constantChar( const CodeLocation &, std::string & );175 ast::Expr * build_constantStr( const CodeLocation &, std::string & );176 ast::Expr * build_field_name_FLOATING_FRACTIONconstant( const CodeLocation &, const std::string & str );177 ast::Expr * build_field_name_FLOATING_DECIMALconstant( const CodeLocation &, const std::string & str );178 ast::Expr * build_field_name_FLOATINGconstant( const CodeLocation &, const std::string & str );179 ast::Expr * build_field_name_fraction_constants( const CodeLocation &, ast::Expr * fieldName, ExpressionNode * fracts );180 181 ast::NameExpr * build_varref( const CodeLocation &, const std::string * name );182 ast::QualifiedNameExpr * build_qualified_expr( const CodeLocation &, const DeclarationNode * decl_node, const ast::NameExpr * name );183 ast::QualifiedNameExpr * build_qualified_expr( const CodeLocation &, const ast::EnumDecl * decl, const ast::NameExpr * name );184 ast::DimensionExpr * build_dimensionref( const CodeLocation &, const std::string * name );185 186 ast::Expr * build_cast( const CodeLocation &, DeclarationNode * decl_node, ExpressionNode * expr_node );187 ast::Expr * build_keyword_cast( const CodeLocation &, ast::AggregateDecl::Aggregate target, ExpressionNode * expr_node );188 ast::Expr * build_virtual_cast( const CodeLocation &, DeclarationNode * decl_node, ExpressionNode * expr_node );189 ast::Expr * build_fieldSel( const CodeLocation &, ExpressionNode * expr_node, ast::Expr * member );190 ast::Expr * build_pfieldSel( const CodeLocation &, ExpressionNode * expr_node, ast::Expr * member );191 ast::Expr * build_offsetOf( const CodeLocation &, DeclarationNode * decl_node, ast::NameExpr * member );192 ast::Expr * build_and( const CodeLocation &, ExpressionNode * expr_node1, ExpressionNode * expr_node2 );193 ast::Expr * build_and_or( const CodeLocation &, ExpressionNode * expr_node1, ExpressionNode * expr_node2, ast::LogicalFlag flag );194 ast::Expr * build_unary_val( const CodeLocation &, OperKinds op, ExpressionNode * expr_node );195 ast::Expr * build_binary_val( const CodeLocation &, OperKinds op, ExpressionNode * expr_node1, ExpressionNode * expr_node2 );196 ast::Expr * build_binary_ptr( const CodeLocation &, OperKinds op, ExpressionNode * expr_node1, ExpressionNode * expr_node2 );197 ast::Expr * build_cond( const CodeLocation &, ExpressionNode * expr_node1, ExpressionNode * expr_node2, ExpressionNode * expr_node3 );198 ast::Expr * build_tuple( const CodeLocation &, ExpressionNode * expr_node = nullptr );199 ast::Expr * build_func( const CodeLocation &, ExpressionNode * function, ExpressionNode * expr_node );200 ast::Expr * build_compoundLiteral( const CodeLocation &, DeclarationNode * decl_node, InitializerNode * kids );201 202 //##############################################################################203 204 struct TypeData;205 206 struct DeclarationNode : public ParseNode {207 // These enumerations must harmonize with their names in DeclarationNode.cc.208 enum BasicType {209 Void, Bool, Char, Int, Int128,210 Float, Double, LongDouble, uuFloat80, uuFloat128,211 uFloat16, uFloat32, uFloat32x, uFloat64, uFloat64x, uFloat128, uFloat128x,212 NoBasicType213 };214 static const char * basicTypeNames[];215 enum ComplexType { Complex, NoComplexType, Imaginary }; // Imaginary unsupported => parse, but make invisible and print error message216 static const char * complexTypeNames[];217 enum Signedness { Signed, Unsigned, NoSignedness };218 static const char * signednessNames[];219 enum Length { Short, Long, LongLong, NoLength };220 static const char * lengthNames[];221 enum BuiltinType { Valist, AutoType, Zero, One, NoBuiltinType };222 static const char * builtinTypeNames[];223 224 static DeclarationNode * newStorageClass( ast::Storage::Classes );225 static DeclarationNode * newFuncSpecifier( ast::Function::Specs );226 static DeclarationNode * newTypeQualifier( ast::CV::Qualifiers );227 static DeclarationNode * newBasicType( BasicType );228 static DeclarationNode * newComplexType( ComplexType );229 static DeclarationNode * newSignedNess( Signedness );230 static DeclarationNode * newLength( Length );231 static DeclarationNode * newBuiltinType( BuiltinType );232 static DeclarationNode * newForall( DeclarationNode * );233 static DeclarationNode * newFromTypedef( const std::string * );234 static DeclarationNode * newFromGlobalScope();235 static DeclarationNode * newQualifiedType( DeclarationNode *, DeclarationNode * );236 static DeclarationNode * newFunction( const std::string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body );237 static DeclarationNode * newAggregate( ast::AggregateDecl::Aggregate kind, const std::string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body );238 static DeclarationNode * newEnum( const std::string * name, DeclarationNode * constants, bool body, bool typed, DeclarationNode * base = nullptr, EnumHiding hiding = EnumHiding::Visible );239 static DeclarationNode * newEnumConstant( const std::string * name, ExpressionNode * constant );240 static DeclarationNode * newEnumValueGeneric( const std::string * name, InitializerNode * init );241 static DeclarationNode * newEnumInLine( const std::string name );242 static DeclarationNode * newName( const std::string * );243 static DeclarationNode * newFromTypeGen( const std::string *, ExpressionNode * params );244 static DeclarationNode * newTypeParam( ast::TypeDecl::Kind, const std::string * );245 static DeclarationNode * newTrait( const std::string * name, DeclarationNode * params, DeclarationNode * asserts );246 static DeclarationNode * newTraitUse( const std::string * name, ExpressionNode * params );247 static DeclarationNode * newTypeDecl( const std::string * name, DeclarationNode * typeParams );248 static DeclarationNode * newPointer( DeclarationNode * qualifiers, OperKinds kind );249 static DeclarationNode * newArray( ExpressionNode * size, DeclarationNode * qualifiers, bool isStatic );250 static DeclarationNode * newVarArray( DeclarationNode * qualifiers );251 static DeclarationNode * newBitfield( ExpressionNode * size );252 static DeclarationNode * newTuple( DeclarationNode * members );253 static DeclarationNode * newTypeof( ExpressionNode * expr, bool basetypeof = false );254 static DeclarationNode * newVtableType( DeclarationNode * expr );255 static DeclarationNode * newAttribute( const std::string *, ExpressionNode * expr = nullptr ); // gcc attributes256 static DeclarationNode * newDirectiveStmt( StatementNode * stmt ); // gcc external directive statement257 static DeclarationNode * newAsmStmt( StatementNode * stmt ); // gcc external asm statement258 static DeclarationNode * newStaticAssert( ExpressionNode * condition, ast::Expr * message );259 260 DeclarationNode();261 ~DeclarationNode();262 DeclarationNode * clone() const override;263 264 DeclarationNode * addQualifiers( DeclarationNode * );265 void checkQualifiers( const TypeData *, const TypeData * );266 void checkSpecifiers( DeclarationNode * );267 DeclarationNode * copySpecifiers( DeclarationNode * );268 DeclarationNode * addType( DeclarationNode * );269 DeclarationNode * addTypedef();270 DeclarationNode * addEnumBase( DeclarationNode * );271 DeclarationNode * addAssertions( DeclarationNode * );272 DeclarationNode * addName( std::string * );273 DeclarationNode * addAsmName( DeclarationNode * );274 DeclarationNode * addBitfield( ExpressionNode * size );275 DeclarationNode * addVarArgs();276 DeclarationNode * addFunctionBody( StatementNode * body, ExpressionNode * with = nullptr );277 DeclarationNode * addOldDeclList( DeclarationNode * list );278 DeclarationNode * setBase( TypeData * newType );279 DeclarationNode * copyAttribute( DeclarationNode * attr );280 DeclarationNode * addPointer( DeclarationNode * qualifiers );281 DeclarationNode * addArray( DeclarationNode * array );282 DeclarationNode * addNewPointer( DeclarationNode * pointer );283 DeclarationNode * addNewArray( DeclarationNode * array );284 DeclarationNode * addParamList( DeclarationNode * list );285 DeclarationNode * addIdList( DeclarationNode * list ); // old-style functions286 DeclarationNode * addInitializer( InitializerNode * init );287 DeclarationNode * addTypeInitializer( DeclarationNode * init );288 289 DeclarationNode * cloneType( std::string * newName );290 DeclarationNode * cloneBaseType( DeclarationNode * newdecl );291 292 DeclarationNode * appendList( DeclarationNode * node ) {293 return (DeclarationNode *)set_last( node );294 }295 296 virtual void print( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const override;297 virtual void printList( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const override;298 299 ast::Decl * build() const;300 ast::Type * buildType() const;301 302 ast::Linkage::Spec get_linkage() const { return linkage; }303 DeclarationNode * extractAggregate() const;304 bool has_enumeratorValue() const { return (bool)enumeratorValue; }305 ExpressionNode * consume_enumeratorValue() const { return const_cast<DeclarationNode *>(this)->enumeratorValue.release(); }306 307 bool get_extension() const { return extension; }308 DeclarationNode * set_extension( bool exten ) { extension = exten; return this; }309 310 bool get_inLine() const { return inLine; }311 DeclarationNode * set_inLine( bool inL ) { inLine = inL; return this; }312 313 DeclarationNode * get_last() { return (DeclarationNode *)ParseNode::get_last(); }314 315 struct Variable_t {316 // const std::string * name;317 ast::TypeDecl::Kind tyClass;318 DeclarationNode * assertions;319 DeclarationNode * initializer;320 };321 Variable_t variable;322 323 struct StaticAssert_t {324 ExpressionNode * condition;325 ast::Expr * message;326 };327 StaticAssert_t assert;328 329 BuiltinType builtin = NoBuiltinType;330 331 TypeData * type = nullptr;332 333 bool inLine = false;334 bool enumInLine = false;335 ast::Function::Specs funcSpecs;336 ast::Storage::Classes storageClasses;337 338 ExpressionNode * bitfieldWidth = nullptr;339 std::unique_ptr<ExpressionNode> enumeratorValue;340 bool hasEllipsis = false;341 ast::Linkage::Spec linkage;342 ast::Expr * asmName = nullptr;343 std::vector<ast::ptr<ast::Attribute>> attributes;344 InitializerNode * initializer = nullptr;345 bool extension = false;346 std::string error;347 StatementNode * asmStmt = nullptr;348 StatementNode * directiveStmt = nullptr;349 350 static UniqueName anonymous;351 }; // DeclarationNode352 353 ast::Type * buildType( TypeData * type );354 355 static inline ast::Type * maybeMoveBuildType( const DeclarationNode * orig ) {356 ast::Type * ret = orig ? orig->buildType() : nullptr;357 delete orig;358 return ret;359 }360 361 //##############################################################################362 363 struct StatementNode final : public ParseNode {364 StatementNode() :365 stmt( nullptr ), clause( nullptr ) {}366 StatementNode( ast::Stmt * stmt ) :367 stmt( stmt ), clause( nullptr ) {}368 StatementNode( ast::StmtClause * clause ) :369 stmt( nullptr ), clause( clause ) {}370 StatementNode( DeclarationNode * decl );371 virtual ~StatementNode() {}372 373 virtual StatementNode * clone() const final { assert( false ); return nullptr; }374 ast::Stmt * build() const { return const_cast<StatementNode *>(this)->stmt.release(); }375 376 virtual StatementNode * add_label(377 const CodeLocation & location,378 const std::string * name,379 DeclarationNode * attr = nullptr ) {380 stmt->labels.emplace_back( location,381 *name,382 attr ? std::move( attr->attributes )383 : std::vector<ast::ptr<ast::Attribute>>{} );384 delete attr;385 delete name;386 return this;387 }388 389 virtual StatementNode * append_last_case( StatementNode * );390 391 virtual void print( std::ostream & os, __attribute__((unused)) int indent = 0 ) const override {392 os << stmt.get() << std::endl;393 }394 395 std::unique_ptr<ast::Stmt> stmt;396 std::unique_ptr<ast::StmtClause> clause;397 }; // StatementNode398 399 ast::Stmt * build_expr( CodeLocation const &, ExpressionNode * ctl );400 401 struct CondCtl {402 CondCtl( DeclarationNode * decl, ExpressionNode * condition ) :403 init( decl ? new StatementNode( decl ) : nullptr ), condition( condition ) {}404 405 StatementNode * init;406 ExpressionNode * condition;407 };408 409 struct ForCtrl {410 ForCtrl( StatementNode * stmt, ExpressionNode * condition, ExpressionNode * change ) :411 init( stmt ), condition( condition ), change( change ) {}412 413 StatementNode * init;414 ExpressionNode * condition;415 ExpressionNode * change;416 };417 418 ast::Stmt * build_if( const CodeLocation &, CondCtl * ctl, StatementNode * then, StatementNode * else_ );419 ast::Stmt * build_switch( const CodeLocation &, bool isSwitch, ExpressionNode * ctl, StatementNode * stmt );420 ast::CaseClause * build_case( ExpressionNode * ctl );421 ast::CaseClause * build_default( const CodeLocation & );422 ast::Stmt * build_while( const CodeLocation &, CondCtl * ctl, StatementNode * stmt, StatementNode * else_ = nullptr );423 ast::Stmt * build_do_while( const CodeLocation &, ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ = nullptr );424 ast::Stmt * build_for( const CodeLocation &, ForCtrl * forctl, StatementNode * stmt, StatementNode * else_ = nullptr );425 ast::Stmt * build_branch( const CodeLocation &, ast::BranchStmt::Kind kind );426 ast::Stmt * build_branch( const CodeLocation &, std::string * identifier, ast::BranchStmt::Kind kind );427 ast::Stmt * build_computedgoto( ExpressionNode * ctl );428 ast::Stmt * build_return( const CodeLocation &, ExpressionNode * ctl );429 ast::Stmt * build_throw( const CodeLocation &, ExpressionNode * ctl );430 ast::Stmt * build_resume( const CodeLocation &, ExpressionNode * ctl );431 ast::Stmt * build_resume_at( ExpressionNode * ctl , ExpressionNode * target );432 ast::Stmt * build_try( const CodeLocation &, StatementNode * try_, StatementNode * catch_, StatementNode * finally_ );433 ast::CatchClause * build_catch( const CodeLocation &, ast::ExceptionKind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body );434 ast::FinallyClause * build_finally( const CodeLocation &, StatementNode * stmt );435 ast::Stmt * build_compound( const CodeLocation &, StatementNode * first );436 StatementNode * maybe_build_compound( const CodeLocation &, StatementNode * first );437 ast::Stmt * build_asm( const CodeLocation &, bool voltile, ast::Expr * instruction, ExpressionNode * output = nullptr, ExpressionNode * input = nullptr, ExpressionNode * clobber = nullptr, LabelNode * gotolabels = nullptr );438 ast::Stmt * build_directive( const CodeLocation &, std::string * directive );439 ast::SuspendStmt * build_suspend( const CodeLocation &, StatementNode *, ast::SuspendStmt::Type );440 ast::WaitForStmt * build_waitfor( const CodeLocation &, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt );441 ast::WaitForStmt * build_waitfor_else( const CodeLocation &, ast::WaitForStmt * existing, ExpressionNode * when, StatementNode * stmt );442 ast::WaitForStmt * build_waitfor_timeout( const CodeLocation &, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt );443 ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation &, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt );444 ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation &, ExpressionNode * when, StatementNode * stmt );445 ast::WaitUntilStmt::ClauseNode * build_waituntil_timeout( const CodeLocation &, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt );446 ast::WaitUntilStmt * build_waituntil_stmt( const CodeLocation &, ast::WaitUntilStmt::ClauseNode * root );447 ast::Stmt * build_with( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt );448 ast::Stmt * build_mutex( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt );449 450 //##############################################################################451 452 template<typename AstType, typename NodeType,453 template<typename, typename...> class Container, typename... Args>454 void buildList( const NodeType * firstNode,455 Container<ast::ptr<AstType>, Args...> & output ) {456 SemanticErrorException errors;457 std::back_insert_iterator<Container<ast::ptr<AstType>, Args...>> out( output );458 const NodeType * cur = firstNode;459 460 while ( cur ) {461 try {462 if ( auto result = dynamic_cast<AstType *>( maybeBuild( cur ) ) ) {463 *out++ = result;464 } else {465 assertf(false, __PRETTY_FUNCTION__ );466 SemanticError( cur->location, "type specifier declaration in forall clause is currently unimplemented." );467 } // if468 } catch( SemanticErrorException & e ) {469 errors.append( e );470 } // try471 const ParseNode * temp = cur->get_next();472 // Should not return nullptr, then it is non-homogeneous:473 cur = dynamic_cast<const NodeType *>( temp );474 if ( !cur && temp ) {475 SemanticError( temp->location, "internal error, non-homogeneous nodes founds in buildList processing." );476 } // if477 } // while478 if ( ! errors.isEmpty() ) {479 throw errors;480 } // if481 }482 483 // in DeclarationNode.cc484 void buildList( const DeclarationNode * firstNode, std::vector<ast::ptr<ast::Decl>> & outputList );485 void buildList( const DeclarationNode * firstNode, std::vector<ast::ptr<ast::DeclWithType>> & outputList );486 void buildTypeList( const DeclarationNode * firstNode, std::vector<ast::ptr<ast::Type>> & outputList );487 488 template<typename AstType, typename NodeType,489 template<typename, typename...> class Container, typename... Args>490 void buildMoveList( const NodeType * firstNode,491 Container<ast::ptr<AstType>, Args...> & output ) {492 buildList<AstType, NodeType, Container, Args...>( firstNode, output );493 delete firstNode;494 }495 496 // in ParseNode.cc497 101 std::ostream & operator<<( std::ostream & out, const ParseNode * node ); 498 102 -
src/Parser/RunParser.cpp
ra50fdfb r6e1e2d0 20 20 #include "CodeTools/TrackLoc.h" // for fillLocations 21 21 #include "Common/CodeLocationTools.hpp" // for forceFillCodeLocations 22 #include "Parser/ ParseNode.h"// for DeclarationNode, buildList22 #include "Parser/DeclarationNode.h" // for DeclarationNode, buildList 23 23 #include "Parser/TypedefTable.h" // for TypedefTable 24 24 -
src/Parser/StatementNode.cc
ra50fdfb r6e1e2d0 11 11 // Created On : Sat May 16 14:59:41 2015 12 12 // Last Modified By : Andrew Beach 13 // Last Modified On : Tue Apr 4 11:40:00 202314 // Update Count : 42 713 // Last Modified On : Tue Apr 11 10:16:00 2023 14 // Update Count : 428 15 15 // 16 17 #include "StatementNode.h" 16 18 17 19 #include <cassert> // for assert, strict_dynamic_cast, assertf … … 23 25 #include "Common/SemanticError.h" // for SemanticError 24 26 #include "Common/utility.h" // for maybeMoveBuild, maybeBuild 25 #include "ParseNode.h" // for StatementNode, ExpressionNode, bui... 27 #include "DeclarationNode.h" // for DeclarationNode 28 #include "ExpressionNode.h" // for ExpressionNode 26 29 #include "parserutility.h" // for notZeroExpr 27 30 … … 29 32 30 33 using namespace std; 34 35 // Some helpers for cases that really want a single node but check for lists. 36 static const ast::Stmt * buildMoveSingle( StatementNode * node ) { 37 std::vector<ast::ptr<ast::Stmt>> list; 38 buildMoveList( node, list ); 39 assertf( list.size() == 1, "CFA Internal Error: Extra/Missing Nodes" ); 40 return list.front().release(); 41 } 42 43 static const ast::Stmt * buildMoveOptional( StatementNode * node ) { 44 std::vector<ast::ptr<ast::Stmt>> list; 45 buildMoveList( node, list ); 46 assertf( list.size() <= 1, "CFA Internal Error: Extra Nodes" ); 47 return list.empty() ? nullptr : list.front().release(); 48 } 31 49 32 50 StatementNode::StatementNode( DeclarationNode * decl ) { … … 53 71 } // StatementNode::StatementNode 54 72 55 StatementNode * StatementNode::append_last_case( StatementNode * stmt ) { 56 StatementNode * prev = this; 73 StatementNode * StatementNode::add_label( 74 const CodeLocation & location, 75 const std::string * name, 76 DeclarationNode * attr ) { 77 stmt->labels.emplace_back( location, 78 *name, 79 attr ? std::move( attr->attributes ) 80 : std::vector<ast::ptr<ast::Attribute>>{} ); 81 delete attr; 82 delete name; 83 return this; 84 } 85 86 ClauseNode * ClauseNode::append_last_case( StatementNode * stmt ) { 87 ClauseNode * prev = this; 57 88 // find end of list and maintain previous pointer 58 for ( StatementNode * curr = prev; curr != nullptr; curr = (StatementNode *)curr->get_next() ) { 59 StatementNode * node = strict_dynamic_cast< StatementNode * >(curr); 60 assert( nullptr == node->stmt.get() ); 89 for ( ClauseNode * curr = prev; curr != nullptr; curr = (ClauseNode *)curr->get_next() ) { 90 ClauseNode * node = strict_dynamic_cast< ClauseNode * >(curr); 61 91 assert( dynamic_cast<ast::CaseClause *>( node->clause.get() ) ); 62 92 prev = curr; 63 93 } // for 94 ClauseNode * node = dynamic_cast< ClauseNode * >(prev); 64 95 // convert from StatementNode list to Statement list 65 StatementNode * node = dynamic_cast< StatementNode * >(prev);66 96 std::vector<ast::ptr<ast::Stmt>> stmts; 67 97 buildMoveList( stmt, stmts ); … … 73 103 stmts.clear(); 74 104 return this; 75 } // StatementNode::append_last_case105 } // ClauseNode::append_last_case 76 106 77 107 ast::Stmt * build_expr( CodeLocation const & location, ExpressionNode * ctl ) { … … 97 127 for ( ast::ptr<ast::Stmt> & stmt : inits ) { 98 128 // build the && of all of the declared variables compared against 0 99 //auto declStmt = strict_dynamic_cast<ast::DeclStmt *>( stmt );100 129 auto declStmt = stmt.strict_as<ast::DeclStmt>(); 101 //ast::DeclWithType * dwt = strict_dynamic_cast<ast::DeclWithType *>( declStmt->decl );102 130 auto dwt = declStmt->decl.strict_as<ast::DeclWithType>(); 103 131 ast::Expr * nze = notZeroExpr( new ast::VariableExpr( dwt->location, dwt ) ); … … 113 141 ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set 114 142 115 std::vector<ast::ptr<ast::Stmt>> aststmt; 116 buildMoveList( then, aststmt ); 117 assert( aststmt.size() == 1 ); 118 ast::Stmt const * astthen = aststmt.front().release(); 119 120 ast::Stmt const * astelse = nullptr; 121 if ( else_ ) { 122 std::vector<ast::ptr<ast::Stmt>> aststmt; 123 buildMoveList( else_, aststmt ); 124 assert( aststmt.size() == 1 ); 125 astelse = aststmt.front().release(); 126 } // if 143 ast::Stmt const * astthen = buildMoveSingle( then ); 144 ast::Stmt const * astelse = buildMoveOptional( else_ ); 127 145 128 146 return new ast::IfStmt( location, astcond, astthen, astelse, … … 131 149 } // build_if 132 150 133 // Temporary work around. Split StmtClause off from StatementNode. 134 template<typename clause_t> 135 static void buildMoveClauseList( StatementNode * firstNode, 136 std::vector<ast::ptr<clause_t>> & output ) { 137 SemanticErrorException errors; 138 std::back_insert_iterator<std::vector<ast::ptr<clause_t>>> 139 out( output ); 140 StatementNode * cur = firstNode; 141 142 while ( cur ) { 143 try { 144 auto clause = cur->clause.release(); 145 if ( auto result = dynamic_cast<clause_t *>( clause ) ) { 146 *out++ = result; 147 } else { 148 assertf(false, __PRETTY_FUNCTION__ ); 149 SemanticError( cur->location, "type specifier declaration in forall clause is currently unimplemented." ); 150 } // if 151 } catch( SemanticErrorException & e ) { 152 errors.append( e ); 153 } // try 154 ParseNode * temp = cur->get_next(); 155 // Should not return nullptr, then it is non-homogeneous: 156 cur = dynamic_cast<StatementNode *>( temp ); 157 if ( !cur && temp ) { 158 SemanticError( temp->location, "internal error, non-homogeneous nodes founds in buildList processing." ); 159 } // if 160 } // while 161 if ( ! errors.isEmpty() ) { 162 throw errors; 163 } // if 164 // Usually in the wrapper. 165 delete firstNode; 166 } 167 168 ast::Stmt * build_switch( const CodeLocation & location, bool isSwitch, ExpressionNode * ctl, StatementNode * stmt ) { 151 ast::Stmt * build_switch( const CodeLocation & location, bool isSwitch, ExpressionNode * ctl, ClauseNode * stmt ) { 169 152 std::vector<ast::ptr<ast::CaseClause>> aststmt; 170 buildMove ClauseList( stmt, aststmt );153 buildMoveList( stmt, aststmt ); 171 154 // If it is not a switch it is a choose statement. 172 155 if ( ! isSwitch ) { … … 190 173 } // build_switch 191 174 192 ast::CaseClause * build_case( ExpressionNode * ctl ) {175 ast::CaseClause * build_case( const CodeLocation & location, ExpressionNode * ctl ) { 193 176 // stmt starts empty and then added to 194 177 auto expr = maybeMoveBuild( ctl ); 195 return new ast::CaseClause( expr->location, expr, {} );178 return new ast::CaseClause( location, expr, {} ); 196 179 } // build_case 197 180 … … 205 188 ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set 206 189 207 std::vector<ast::ptr<ast::Stmt>> aststmt; // loop body, compound created if empty208 buildMoveList( stmt, aststmt );209 assert( aststmt.size() == 1 );210 211 std::vector<ast::ptr<ast::Stmt>> astelse; // else clause, maybe empty212 buildMoveList( else_, astelse );213 assert( astelse.size() <= 1 );214 215 190 return new ast::WhileDoStmt( location, 216 191 astcond, 217 aststmt.front(),218 astelse.empty() ? nullptr : astelse.front().release(),192 buildMoveSingle( stmt ), 193 buildMoveOptional( else_ ), 219 194 std::move( astinit ), 220 false195 ast::While 221 196 ); 222 197 } // build_while 223 198 224 199 ast::Stmt * build_do_while( const CodeLocation & location, ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ ) { 225 std::vector<ast::ptr<ast::Stmt>> aststmt; // loop body, compound created if empty226 buildMoveList( stmt, aststmt );227 assert( aststmt.size() == 1 ); // compound created if empty228 229 std::vector<ast::ptr<ast::Stmt>> astelse; // else clause, maybe empty230 buildMoveList( else_, astelse );231 assert( astelse.size() <= 1 );232 233 200 // do-while cannot have declarations in the contitional, so init is always empty 234 201 return new ast::WhileDoStmt( location, 235 202 notZeroExpr( maybeMoveBuild( ctl ) ), 236 aststmt.front(),237 astelse.empty() ? nullptr : astelse.front().release(),203 buildMoveSingle( stmt ), 204 buildMoveOptional( else_ ), 238 205 {}, 239 true206 ast::DoWhile 240 207 ); 241 208 } // build_do_while … … 251 218 astincr = maybeMoveBuild( forctl->change ); 252 219 delete forctl; 253 254 std::vector<ast::ptr<ast::Stmt>> aststmt; // loop body, compound created if empty255 buildMoveList( stmt, aststmt );256 assert( aststmt.size() == 1 );257 258 std::vector<ast::ptr<ast::Stmt>> astelse; // else clause, maybe empty259 buildMoveList( else_, astelse );260 assert( astelse.size() <= 1 );261 220 262 221 return new ast::ForStmt( location, … … 264 223 astcond, 265 224 astincr, 266 aststmt.front(),267 astelse.empty() ? nullptr : astelse.front().release()225 buildMoveSingle( stmt ), 226 buildMoveOptional( else_ ) 268 227 ); 269 228 } // build_for … … 326 285 } // build_resume_at 327 286 328 ast::Stmt * build_try( const CodeLocation & location, StatementNode * try_, StatementNode * catch_, StatementNode * finally_ ) {287 ast::Stmt * build_try( const CodeLocation & location, StatementNode * try_, ClauseNode * catch_, ClauseNode * finally_ ) { 329 288 std::vector<ast::ptr<ast::CatchClause>> aststmt; 330 buildMove ClauseList( catch_, aststmt );289 buildMoveList( catch_, aststmt ); 331 290 ast::CompoundStmt * tryBlock = strict_dynamic_cast<ast::CompoundStmt *>( maybeMoveBuild( try_ ) ); 332 291 ast::FinallyClause * finallyBlock = nullptr; … … 342 301 343 302 ast::CatchClause * build_catch( const CodeLocation & location, ast::ExceptionKind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body ) { 344 std::vector<ast::ptr<ast::Stmt>> aststmt;345 buildMoveList( body, aststmt );346 assert( aststmt.size() == 1 );347 303 return new ast::CatchClause( location, 348 304 kind, 349 305 maybeMoveBuild( decl ), 350 306 maybeMoveBuild( cond ), 351 aststmt.front().release()307 buildMoveSingle( body ) 352 308 ); 353 309 } // build_catch 354 310 355 311 ast::FinallyClause * build_finally( const CodeLocation & location, StatementNode * stmt ) { 356 std::vector<ast::ptr<ast::Stmt>> aststmt;357 buildMoveList( stmt, aststmt );358 assert( aststmt.size() == 1 );359 312 return new ast::FinallyClause( location, 360 aststmt.front().strict_as<ast::CompoundStmt>() 313 strict_dynamic_cast<const ast::CompoundStmt *>( 314 buildMoveSingle( stmt ) 315 ) 361 316 ); 362 317 } // build_finally 363 318 364 ast::SuspendStmt * build_suspend( const CodeLocation & location, StatementNode * then, ast::SuspendStmt::Type type ) { 365 std::vector<ast::ptr<ast::Stmt>> stmts; 366 buildMoveList( then, stmts ); 367 ast::CompoundStmt const * then2 = nullptr; 368 if(!stmts.empty()) { 369 assert( stmts.size() == 1 ); 370 then2 = stmts.front().strict_as<ast::CompoundStmt>(); 371 } 372 auto node = new ast::SuspendStmt( location, then2, ast::SuspendStmt::None ); 373 node->type = type; 374 return node; 319 ast::SuspendStmt * build_suspend( const CodeLocation & location, StatementNode * then, ast::SuspendStmt::Kind kind ) { 320 return new ast::SuspendStmt( location, 321 strict_dynamic_cast<const ast::CompoundStmt *, nullptr>( 322 buildMoveOptional( then ) 323 ), 324 kind 325 ); 375 326 } // build_suspend 376 327 … … 525 476 526 477 // Question 527 ast::Stmt * build_asm( const CodeLocation & location, bool voltile, ast::Expr* instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) {478 ast::Stmt * build_asm( const CodeLocation & location, bool is_volatile, ExpressionNode * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) { 528 479 std::vector<ast::ptr<ast::Expr>> out, in; 529 480 std::vector<ast::ptr<ast::ConstantExpr>> clob; … … 533 484 buildMoveList( clobber, clob ); 534 485 return new ast::AsmStmt( location, 535 voltile,536 instruction,486 is_volatile, 487 maybeMoveBuild( instruction ), 537 488 std::move( out ), 538 489 std::move( in ), -
src/Parser/TypeData.cc
ra50fdfb r6e1e2d0 24 24 #include "Common/SemanticError.h" // for SemanticError 25 25 #include "Common/utility.h" // for splice, spliceBegin 26 #include "Parser/ parserutility.h" // for maybeCopy, maybeBuild, maybeMoveB...27 #include "Parser/ ParseNode.h" // for DeclarationNode, ExpressionNode26 #include "Parser/ExpressionNode.h" // for ExpressionNode 27 #include "Parser/StatementNode.h" // for StatementNode 28 28 29 29 class Attribute; … … 1397 1397 std::move( attributes ), 1398 1398 funcSpec, 1399 isVarArgs1399 (isVarArgs) ? ast::VariableArgs : ast::FixedArgs 1400 1400 ); 1401 1401 buildList( td->function.withExprs, decl->withExprs ); -
src/Parser/TypeData.h
ra50fdfb r6e1e2d0 16 16 #pragma once 17 17 18 #include <iosfwd> 19 #include <list> 20 #include <string> 18 #include <iosfwd> // for ostream 19 #include <list> // for list 20 #include <string> // for string 21 21 22 #include "AST/Type.hpp" 23 #include " ParseNode.h" // for DeclarationNode, DeclarationNode::Ag...22 #include "AST/Type.hpp" // for Type 23 #include "DeclarationNode.h" // for DeclarationNode 24 24 25 25 struct TypeData { -
src/Parser/TypedefTable.cc
ra50fdfb r6e1e2d0 16 16 17 17 #include "TypedefTable.h" 18 #include <cassert> // for assert 19 #include <iostream> 18 19 #include <cassert> // for assert 20 #include <string> // for string 21 #include <iostream> // for iostream 22 23 #include "ExpressionNode.h" // for LabelNode 24 #include "ParserTypes.h" // for Token 25 #include "StatementNode.h" // for CondCtl, ForCtrl 26 // This (generated) header must come late as it is missing includes. 27 #include "parser.hh" // for IDENTIFIER, TYPEDEFname, TYPEGENname 28 20 29 using namespace std; 21 30 22 31 #if 0 23 32 #define debugPrint( code ) code 33 34 static const char *kindName( int kind ) { 35 switch ( kind ) { 36 case IDENTIFIER: return "identifier"; 37 case TYPEDIMname: return "typedim"; 38 case TYPEDEFname: return "typedef"; 39 case TYPEGENname: return "typegen"; 40 default: 41 cerr << "Error: cfa-cpp internal error, invalid kind of identifier" << endl; 42 abort(); 43 } // switch 44 } // kindName 24 45 #else 25 46 #define debugPrint( code ) 26 47 #endif 27 28 using namespace std; // string, iostream29 30 debugPrint(31 static const char *kindName( int kind ) {32 switch ( kind ) {33 case IDENTIFIER: return "identifier";34 case TYPEDIMname: return "typedim";35 case TYPEDEFname: return "typedef";36 case TYPEGENname: return "typegen";37 default:38 cerr << "Error: cfa-cpp internal error, invalid kind of identifier" << endl;39 abort();40 } // switch41 } // kindName42 );43 48 44 49 TypedefTable::~TypedefTable() { … … 78 83 typedefTable.addToEnclosingScope( name, kind, "MTD" ); 79 84 } // if 85 } // TypedefTable::makeTypedef 86 87 void TypedefTable::makeTypedef( const string & name ) { 88 return makeTypedef( name, TYPEDEFname ); 80 89 } // TypedefTable::makeTypedef 81 90 -
src/Parser/TypedefTable.h
ra50fdfb r6e1e2d0 19 19 20 20 #include "Common/ScopedMap.h" // for ScopedMap 21 #include "ParserTypes.h"22 #include "parser.hh" // for IDENTIFIER, TYPEDEFname, TYPEGENname23 21 24 22 class TypedefTable { 25 23 struct Note { size_t level; bool forall; }; 26 24 typedef ScopedMap< std::string, int, Note > KindTable; 27 KindTable kindTable; 25 KindTable kindTable; 28 26 unsigned int level = 0; 29 27 public: … … 33 31 bool existsCurr( const std::string & identifier ) const; 34 32 int isKind( const std::string & identifier ) const; 35 void makeTypedef( const std::string & name, int kind = TYPEDEFname ); 33 void makeTypedef( const std::string & name, int kind ); 34 void makeTypedef( const std::string & name ); 36 35 void addToScope( const std::string & identifier, int kind, const char * ); 37 36 void addToEnclosingScope( const std::string & identifier, int kind, const char * ); -
src/Parser/lex.ll
ra50fdfb r6e1e2d0 44 44 45 45 #include "config.h" // configure info 46 #include "DeclarationNode.h" // for DeclarationNode 47 #include "ExpressionNode.h" // for LabelNode 48 #include "InitializerNode.h" // for InitializerNode 46 49 #include "ParseNode.h" 50 #include "ParserTypes.h" // for Token 51 #include "StatementNode.h" // for CondCtl, ForCtrl 47 52 #include "TypedefTable.h" 53 // This (generated) header must come late as it is missing includes. 54 #include "parser.hh" // generated info 48 55 49 56 string * build_postfix_name( string * name ); -
src/Parser/module.mk
ra50fdfb r6e1e2d0 21 21 SRC += \ 22 22 Parser/DeclarationNode.cc \ 23 Parser/DeclarationNode.h \ 23 24 Parser/ExpressionNode.cc \ 25 Parser/ExpressionNode.h \ 24 26 Parser/InitializerNode.cc \ 27 Parser/InitializerNode.h \ 25 28 Parser/lex.ll \ 26 29 Parser/ParseNode.cc \ … … 33 36 Parser/RunParser.hpp \ 34 37 Parser/StatementNode.cc \ 38 Parser/StatementNode.h \ 35 39 Parser/TypeData.cc \ 36 40 Parser/TypeData.h \ -
src/Parser/parser.yy
ra50fdfb r6e1e2d0 9 9 // Author : Peter A. Buhr 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 // Last Modified By : Andrew Beach12 // Last Modified On : Tue Apr 4 14:02:00202313 // Update Count : 63 2911 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Apr 26 16:45:37 2023 13 // Update Count : 6330 14 14 // 15 15 … … 48 48 using namespace std; 49 49 50 #include "SynTree/Declaration.h" 51 #include "ParseNode.h" 50 #include "SynTree/Type.h" // for Type 51 #include "DeclarationNode.h" // for DeclarationNode, ... 52 #include "ExpressionNode.h" // for ExpressionNode, ... 53 #include "InitializerNode.h" // for InitializerNode, ... 54 #include "ParserTypes.h" 55 #include "StatementNode.h" // for build_... 52 56 #include "TypedefTable.h" 53 57 #include "TypeData.h" 54 #include "SynTree/LinkageSpec.h"55 58 #include "Common/SemanticError.h" // error_str 56 59 #include "Common/utility.h" // for maybeMoveBuild, maybeBuild, CodeLo... … … 297 300 %union { 298 301 Token tok; 299 ParseNode * pn; 300 ExpressionNode * en; 302 ExpressionNode * expr; 301 303 DeclarationNode * decl; 302 304 ast::AggregateDecl::Aggregate aggKey; 303 305 ast::TypeDecl::Kind tclass; 304 StatementNode * sn; 306 StatementNode * stmt; 307 ClauseNode * clause; 305 308 ast::WaitForStmt * wfs; 306 ast::WaitUntilStmt::ClauseNode * wuscn; 307 ast::Expr * constant; 309 ast::WaitUntilStmt::ClauseNode * wucn; 308 310 CondCtl * ifctl; 309 ForCtrl * fctl; 310 OperKinds compop; 311 LabelNode * label; 312 InitializerNode * in; 313 OperKinds op; 311 ForCtrl * forctl; 312 LabelNode * labels; 313 InitializerNode * init; 314 OperKinds oper; 314 315 std::string * str; 315 bool flag;316 EnumHiding hide;317 ast::ExceptionKind catch_kind;316 bool is_volatile; 317 EnumHiding enum_hiding; 318 ast::ExceptionKind except_kind; 318 319 ast::GenericExpr * genexpr; 319 320 } … … 381 382 %type<tok> identifier identifier_at identifier_or_type_name attr_name 382 383 %type<tok> quasi_keyword 383 %type< constant> string_literal384 %type<expr> string_literal 384 385 %type<str> string_literal_list 385 386 386 %type< hide> hide_opt visible_hide_opt387 %type<enum_hiding> hide_opt visible_hide_opt 387 388 388 389 // expressions 389 %type<e n> constant390 %type<e n> tuple tuple_expression_list391 %type<op > ptrref_operator unary_operator assignment_operator simple_assignment_operator compound_assignment_operator392 %type<e n> primary_expression postfix_expression unary_expression393 %type<e n> cast_expression_list cast_expression exponential_expression multiplicative_expression additive_expression394 %type<e n> shift_expression relational_expression equality_expression395 %type<e n> AND_expression exclusive_OR_expression inclusive_OR_expression396 %type<e n> logical_AND_expression logical_OR_expression397 %type<e n> conditional_expression constant_expression assignment_expression assignment_expression_opt398 %type<e n> comma_expression comma_expression_opt399 %type<e n> argument_expression_list_opt argument_expression_list argument_expression default_initializer_opt390 %type<expr> constant 391 %type<expr> tuple tuple_expression_list 392 %type<oper> ptrref_operator unary_operator assignment_operator simple_assignment_operator compound_assignment_operator 393 %type<expr> primary_expression postfix_expression unary_expression 394 %type<expr> cast_expression_list cast_expression exponential_expression multiplicative_expression additive_expression 395 %type<expr> shift_expression relational_expression equality_expression 396 %type<expr> AND_expression exclusive_OR_expression inclusive_OR_expression 397 %type<expr> logical_AND_expression logical_OR_expression 398 %type<expr> conditional_expression constant_expression assignment_expression assignment_expression_opt 399 %type<expr> comma_expression comma_expression_opt 400 %type<expr> argument_expression_list_opt argument_expression_list argument_expression default_initializer_opt 400 401 %type<ifctl> conditional_declaration 401 %type<f ctl> for_control_expression for_control_expression_list402 %type< compop> upupeq updown updowneq downupdowneq403 %type<e n> subrange402 %type<forctl> for_control_expression for_control_expression_list 403 %type<oper> upupeq updown updowneq downupdowneq 404 %type<expr> subrange 404 405 %type<decl> asm_name_opt 405 %type<e n> asm_operands_opt asm_operands_list asm_operand406 %type<label > label_list407 %type<e n> asm_clobbers_list_opt408 %type< flag> asm_volatile_opt409 %type<e n> handler_predicate_opt406 %type<expr> asm_operands_opt asm_operands_list asm_operand 407 %type<labels> label_list 408 %type<expr> asm_clobbers_list_opt 409 %type<is_volatile> asm_volatile_opt 410 %type<expr> handler_predicate_opt 410 411 %type<genexpr> generic_association generic_assoc_list 411 412 412 413 // statements 413 %type<sn> statement labeled_statement compound_statement 414 %type<sn> statement_decl statement_decl_list statement_list_nodecl 415 %type<sn> selection_statement if_statement 416 %type<sn> switch_clause_list_opt switch_clause_list 417 %type<en> case_value 418 %type<sn> case_clause case_value_list case_label case_label_list 419 %type<sn> iteration_statement jump_statement 420 %type<sn> expression_statement asm_statement 421 %type<sn> with_statement 422 %type<en> with_clause_opt 423 %type<sn> exception_statement handler_clause finally_clause 424 %type<catch_kind> handler_key 425 %type<sn> mutex_statement 426 %type<en> when_clause when_clause_opt waitfor waituntil timeout 427 %type<sn> waitfor_statement waituntil_statement 414 %type<stmt> statement labeled_statement compound_statement 415 %type<stmt> statement_decl statement_decl_list statement_list_nodecl 416 %type<stmt> selection_statement if_statement 417 %type<clause> switch_clause_list_opt switch_clause_list 418 %type<expr> case_value 419 %type<clause> case_clause case_value_list case_label case_label_list 420 %type<stmt> iteration_statement jump_statement 421 %type<stmt> expression_statement asm_statement 422 %type<stmt> with_statement 423 %type<expr> with_clause_opt 424 %type<stmt> exception_statement 425 %type<clause> handler_clause finally_clause 426 %type<except_kind> handler_key 427 %type<stmt> mutex_statement 428 %type<expr> when_clause when_clause_opt waitfor waituntil timeout 429 %type<stmt> waitfor_statement waituntil_statement 428 430 %type<wfs> wor_waitfor_clause 429 %type<wu scn> waituntil_clause wand_waituntil_clause wor_waituntil_clause431 %type<wucn> waituntil_clause wand_waituntil_clause wor_waituntil_clause 430 432 431 433 // declarations … … 439 441 %type<decl> assertion assertion_list assertion_list_opt 440 442 441 %type<e n> bit_subrange_size_opt bit_subrange_size443 %type<expr> bit_subrange_size_opt bit_subrange_size 442 444 443 445 %type<decl> basic_declaration_specifier basic_type_name basic_type_specifier direct_type indirect_type … … 452 454 453 455 %type<decl> enumerator_list enum_type enum_type_nobody 454 %type<in > enumerator_value_opt456 %type<init> enumerator_value_opt 455 457 456 458 %type<decl> external_definition external_definition_list external_definition_list_opt … … 459 461 460 462 %type<decl> field_declaration_list_opt field_declaration field_declaring_list_opt field_declarator field_abstract_list_opt field_abstract 461 %type<e n> field field_name_list field_name fraction_constants_opt463 %type<expr> field field_name_list field_name fraction_constants_opt 462 464 463 465 %type<decl> external_function_definition function_definition function_array function_declarator function_no_ptr function_ptr … … 508 510 %type<decl> type_parameter type_parameter_list type_initializer_opt 509 511 510 %type<e n> type_parameters_opt type_list array_type_list512 %type<expr> type_parameters_opt type_list array_type_list 511 513 512 514 %type<decl> type_qualifier type_qualifier_name forall type_qualifier_list_opt type_qualifier_list … … 519 521 520 522 // initializers 521 %type<in > initializer initializer_list_opt initializer_opt523 %type<init> initializer initializer_list_opt initializer_opt 522 524 523 525 // designators 524 %type<e n> designator designator_list designation526 %type<expr> designator designator_list designation 525 527 526 528 … … 644 646 645 647 string_literal: 646 string_literal_list { $$ = build_constantStr( yylloc, *$1); }648 string_literal_list { $$ = new ExpressionNode( build_constantStr( yylloc, *$1 ) ); } 647 649 ; 648 650 … … 739 741 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, $1, $3 ) ); } 740 742 | string_literal '[' assignment_expression ']' // "abc"[3], 3["abc"] 741 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, new ExpressionNode( $1 ), $3 ) ); }743 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, $1, $3 ) ); } 742 744 | postfix_expression '{' argument_expression_list_opt '}' // CFA, constructor call 743 745 { … … 757 759 { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, build_postfix_name( $3 ) ) ), $1 ) ); } 758 760 | string_literal '`' identifier // CFA, postfix call 759 { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, build_postfix_name( $3 ) ) ), new ExpressionNode( $1 )) ); }761 { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, build_postfix_name( $3 ) ) ), $1 ) ); } 760 762 | postfix_expression '.' identifier 761 763 { $$ = new ExpressionNode( build_fieldSel( yylloc, $1, build_varref( yylloc, $3 ) ) ); } … … 857 859 | constant 858 860 | string_literal 859 { $$ = new ExpressionNode( $1 ); }861 { $$ = $1; } 860 862 | EXTENSION cast_expression // GCC 861 863 { $$ = $2->set_extension( true ); } … … 1260 1262 1261 1263 case_value_list: // CFA 1262 case_value { $$ = new StatementNode( build_case($1 ) ); }1264 case_value { $$ = new ClauseNode( build_case( yylloc, $1 ) ); } 1263 1265 // convert case list, e.g., "case 1, 3, 5:" into "case 1: case 3: case 5" 1264 | case_value_list ',' case_value { $$ = (StatementNode *)($1->set_last( new StatementNode( build_case( $3 )) ) ); }1266 | case_value_list ',' case_value { $$ = $1->set_last( new ClauseNode( build_case( yylloc, $3 ) ) ); } 1265 1267 ; 1266 1268 … … 1271 1273 | CASE case_value_list error // syntax error 1272 1274 { SemanticError( yylloc, "Missing colon after case list." ); $$ = nullptr; } 1273 | DEFAULT ':' { $$ = new StatementNode( build_default( yylloc ) ); }1275 | DEFAULT ':' { $$ = new ClauseNode( build_default( yylloc ) ); } 1274 1276 // A semantic check is required to ensure only one default clause per switch/choose statement. 1275 1277 | DEFAULT error // syntax error … … 1279 1281 case_label_list: // CFA 1280 1282 case_label 1281 | case_label_list case_label { $$ = (StatementNode *)( $1->set_last( $2 )); }1283 | case_label_list case_label { $$ = $1->set_last( $2 ); } 1282 1284 ; 1283 1285 … … 1296 1298 { $$ = $1->append_last_case( new StatementNode( build_compound( yylloc, $2 ) ) ); } 1297 1299 | switch_clause_list case_label_list statement_list_nodecl 1298 { $$ = (StatementNode *)( $1->set_last( $2->append_last_case( new StatementNode( build_compound( yylloc, $3 )) ) ) ); }1300 { $$ = $1->set_last( $2->append_last_case( new StatementNode( build_compound( yylloc, $3 ) ) ) ); } 1299 1301 ; 1300 1302 … … 1679 1681 1680 1682 waituntil: 1681 WAITUNTIL '(' c ast_expression ')'1683 WAITUNTIL '(' comma_expression ')' 1682 1684 { $$ = $3; } 1683 1685 ; … … 1736 1738 handler_clause: 1737 1739 handler_key '(' push exception_declaration pop handler_predicate_opt ')' compound_statement 1738 { $$ = new StatementNode( build_catch( yylloc, $1, $4, $6, $8 ) ); }1740 { $$ = new ClauseNode( build_catch( yylloc, $1, $4, $6, $8 ) ); } 1739 1741 | handler_clause handler_key '(' push exception_declaration pop handler_predicate_opt ')' compound_statement 1740 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( yylloc, $2, $5, $7, $9 ) ) ); }1742 { $$ = $1->set_last( new ClauseNode( build_catch( yylloc, $2, $5, $7, $9 ) ) ); } 1741 1743 ; 1742 1744 … … 1755 1757 1756 1758 finally_clause: 1757 FINALLY compound_statement { $$ = new StatementNode( build_finally( yylloc, $2 ) ); }1759 FINALLY compound_statement { $$ = new ClauseNode( build_finally( yylloc, $2 ) ); } 1758 1760 ; 1759 1761 … … 1813 1815 asm_operand: // GCC 1814 1816 string_literal '(' constant_expression ')' 1815 { $$ = new ExpressionNode( new ast::AsmExpr( yylloc, "", $1, maybeMoveBuild( $3 ) ) ); }1817 { $$ = new ExpressionNode( new ast::AsmExpr( yylloc, "", maybeMoveBuild( $1 ), maybeMoveBuild( $3 ) ) ); } 1816 1818 | '[' IDENTIFIER ']' string_literal '(' constant_expression ')' 1817 1819 { 1818 $$ = new ExpressionNode( new ast::AsmExpr( yylloc, *$2.str, $4, maybeMoveBuild( $6 ) ) );1820 $$ = new ExpressionNode( new ast::AsmExpr( yylloc, *$2.str, maybeMoveBuild( $4 ), maybeMoveBuild( $6 ) ) ); 1819 1821 delete $2.str; 1820 1822 } … … 1825 1827 { $$ = nullptr; } // use default argument 1826 1828 | string_literal 1827 { $$ = new ExpressionNode( $1 ); }1829 { $$ = $1; } 1828 1830 | asm_clobbers_list_opt ',' string_literal 1829 { $$ = (ExpressionNode *)( $1->set_last( new ExpressionNode( $3 ) )); }1831 { $$ = (ExpressionNode *)( $1->set_last( $3 ) ); } 1830 1832 ; 1831 1833 … … 1899 1901 static_assert: 1900 1902 STATICASSERT '(' constant_expression ',' string_literal ')' ';' // C11 1901 { $$ = DeclarationNode::newStaticAssert( $3, $5); }1903 { $$ = DeclarationNode::newStaticAssert( $3, maybeMoveBuild( $5 ) ); } 1902 1904 | STATICASSERT '(' constant_expression ')' ';' // CFA 1903 1905 { $$ = DeclarationNode::newStaticAssert( $3, build_constantStr( yylloc, *new string( "\"\"" ) ) ); } … … 3329 3331 { 3330 3332 DeclarationNode * name = new DeclarationNode(); 3331 name->asmName = $3;3333 name->asmName = maybeMoveBuild( $3 ); 3332 3334 $$ = name->addQualifiers( $5 ); 3333 3335 } -
src/Parser/parserutility.h
ra50fdfb r6e1e2d0 24 24 25 25 template< typename T > 26 static inline auto maybeBuild( const T *orig ) -> decltype(orig->build()) {26 static inline auto maybeBuild( T * orig ) -> decltype(orig->build()) { 27 27 return (orig) ? orig->build() : nullptr; 28 28 } 29 29 30 30 template< typename T > 31 static inline auto maybeMoveBuild( const T *orig ) -> decltype(orig->build()) {31 static inline auto maybeMoveBuild( T * orig ) -> decltype(orig->build()) { 32 32 auto ret = maybeBuild<T>(orig); 33 33 delete orig; -
src/ResolvExpr/CandidateFinder.cpp
ra50fdfb r6e1e2d0 55 55 namespace ResolvExpr { 56 56 57 /// Unique identifier for matching expression resolutions to their requesting expression 58 UniqueId globalResnSlot = 0; 59 60 namespace { 61 /// First index is which argument, second is which alternative, third is which exploded element 62 using ExplodedArgs_new = std::deque< std::vector< ExplodedArg > >; 63 64 /// Returns a list of alternatives with the minimum cost in the given list 65 CandidateList findMinCost( const CandidateList & candidates ) { 66 CandidateList out; 67 Cost minCost = Cost::infinity; 68 for ( const CandidateRef & r : candidates ) { 69 if ( r->cost < minCost ) { 70 minCost = r->cost; 71 out.clear(); 72 out.emplace_back( r ); 73 } else if ( r->cost == minCost ) { 74 out.emplace_back( r ); 75 } 76 } 77 return out; 78 } 79 80 /// Computes conversion cost for a given expression to a given type 81 const ast::Expr * computeExpressionConversionCost( 82 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost 83 ) { 84 Cost convCost = computeConversionCost( 85 arg->result, paramType, arg->get_lvalue(), symtab, env ); 86 outCost += convCost; 87 88 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires 89 // conversion. Ignore poly cost for now, since this requires resolution of the cast to 90 // infer parameters and this does not currently work for the reason stated below 91 Cost tmpCost = convCost; 92 tmpCost.incPoly( -tmpCost.get_polyCost() ); 93 if ( tmpCost != Cost::zero ) { 94 ast::ptr< ast::Type > newType = paramType; 95 env.apply( newType ); 96 return new ast::CastExpr{ arg, newType }; 97 98 // xxx - *should* be able to resolve this cast, but at the moment pointers are not 99 // castable to zero_t, but are implicitly convertible. This is clearly inconsistent, 100 // once this is fixed it should be possible to resolve the cast. 101 // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable, 102 // but it shouldn't be because this makes the conversion from DT* to DT* since 103 // commontype(zero_t, DT*) is DT*, rather than nothing 104 105 // CandidateFinder finder{ symtab, env }; 106 // finder.find( arg, ResolvMode::withAdjustment() ); 107 // assertf( finder.candidates.size() > 0, 108 // "Somehow castable expression failed to find alternatives." ); 109 // assertf( finder.candidates.size() == 1, 110 // "Somehow got multiple alternatives for known cast expression." ); 111 // return finder.candidates.front()->expr; 112 } 113 114 return arg; 115 } 116 117 /// Computes conversion cost for a given candidate 118 Cost computeApplicationConversionCost( 119 CandidateRef cand, const ast::SymbolTable & symtab 120 ) { 121 auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >(); 122 auto pointer = appExpr->func->result.strict_as< ast::PointerType >(); 123 auto function = pointer->base.strict_as< ast::FunctionType >(); 124 125 Cost convCost = Cost::zero; 126 const auto & params = function->params; 127 auto param = params.begin(); 128 auto & args = appExpr->args; 129 130 for ( unsigned i = 0; i < args.size(); ++i ) { 131 const ast::Type * argType = args[i]->result; 132 PRINT( 133 std::cerr << "arg expression:" << std::endl; 134 ast::print( std::cerr, args[i], 2 ); 135 std::cerr << "--- results are" << std::endl; 136 ast::print( std::cerr, argType, 2 ); 137 ) 138 139 if ( param == params.end() ) { 140 if ( function->isVarArgs ) { 141 convCost.incUnsafe(); 142 PRINT( std::cerr << "end of params with varargs function: inc unsafe: " 143 << convCost << std::endl; ; ) 144 // convert reference-typed expressions into value-typed expressions 145 cand->expr = ast::mutate_field_index( 146 appExpr, &ast::ApplicationExpr::args, i, 147 referenceToRvalueConversion( args[i], convCost ) ); 148 continue; 149 } else return Cost::infinity; 150 } 151 152 if ( auto def = args[i].as< ast::DefaultArgExpr >() ) { 153 // Default arguments should be free - don't include conversion cost. 154 // Unwrap them here because they are not relevant to the rest of the system 155 cand->expr = ast::mutate_field_index( 156 appExpr, &ast::ApplicationExpr::args, i, def->expr ); 157 ++param; 158 continue; 159 } 160 161 // mark conversion cost and also specialization cost of param type 162 // const ast::Type * paramType = (*param)->get_type(); 163 cand->expr = ast::mutate_field_index( 164 appExpr, &ast::ApplicationExpr::args, i, 165 computeExpressionConversionCost( 166 args[i], *param, symtab, cand->env, convCost ) ); 167 convCost.decSpec( specCost( *param ) ); 168 ++param; // can't be in for-loop update because of the continue 169 } 170 171 if ( param != params.end() ) return Cost::infinity; 172 173 // specialization cost of return types can't be accounted for directly, it disables 174 // otherwise-identical calls, like this example based on auto-newline in the I/O lib: 175 // 176 // forall(otype OS) { 177 // void ?|?(OS&, int); // with newline 178 // OS& ?|?(OS&, int); // no newline, always chosen due to more specialization 179 // } 180 181 // mark type variable and specialization cost of forall clause 182 convCost.incVar( function->forall.size() ); 183 convCost.decSpec( function->assertions.size() ); 184 185 return convCost; 186 } 187 188 void makeUnifiableVars( 189 const ast::FunctionType * type, ast::OpenVarSet & unifiableVars, 190 ast::AssertionSet & need 191 ) { 192 for ( auto & tyvar : type->forall ) { 193 unifiableVars[ *tyvar ] = ast::TypeData{ tyvar->base }; 194 } 195 for ( auto & assn : type->assertions ) { 196 need[ assn ].isUsed = true; 197 } 198 } 199 200 /// Gets a default value from an initializer, nullptr if not present 201 const ast::ConstantExpr * getDefaultValue( const ast::Init * init ) { 202 if ( auto si = dynamic_cast< const ast::SingleInit * >( init ) ) { 203 if ( auto ce = si->value.as< ast::CastExpr >() ) { 204 return ce->arg.as< ast::ConstantExpr >(); 205 } else { 206 return si->value.as< ast::ConstantExpr >(); 207 } 208 } 209 return nullptr; 210 } 211 212 /// State to iteratively build a match of parameter expressions to arguments 213 struct ArgPack { 214 std::size_t parent; ///< Index of parent pack 215 ast::ptr< ast::Expr > expr; ///< The argument stored here 216 Cost cost; ///< The cost of this argument 217 ast::TypeEnvironment env; ///< Environment for this pack 218 ast::AssertionSet need; ///< Assertions outstanding for this pack 219 ast::AssertionSet have; ///< Assertions found for this pack 220 ast::OpenVarSet open; ///< Open variables for this pack 221 unsigned nextArg; ///< Index of next argument in arguments list 222 unsigned tupleStart; ///< Number of tuples that start at this index 223 unsigned nextExpl; ///< Index of next exploded element 224 unsigned explAlt; ///< Index of alternative for nextExpl > 0 225 226 ArgPack() 227 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ), 228 tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {} 229 230 ArgPack( 231 const ast::TypeEnvironment & env, const ast::AssertionSet & need, 232 const ast::AssertionSet & have, const ast::OpenVarSet & open ) 233 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ), 234 open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {} 235 236 ArgPack( 237 std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env, 238 ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open, 239 unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero, 240 unsigned nextExpl = 0, unsigned explAlt = 0 ) 241 : parent(parent), expr( expr ), cost( cost ), env( std::move( env ) ), need( std::move( need ) ), 242 have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ), 243 nextExpl( nextExpl ), explAlt( explAlt ) {} 244 245 ArgPack( 246 const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 247 ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added ) 248 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( std::move( env ) ), 249 need( std::move( need ) ), have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ), 250 tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {} 251 252 /// true if this pack is in the middle of an exploded argument 253 bool hasExpl() const { return nextExpl > 0; } 254 255 /// Gets the list of exploded candidates for this pack 256 const ExplodedArg & getExpl( const ExplodedArgs_new & args ) const { 257 return args[ nextArg-1 ][ explAlt ]; 258 } 259 260 /// Ends a tuple expression, consolidating the appropriate args 261 void endTuple( const std::vector< ArgPack > & packs ) { 262 // add all expressions in tuple to list, summing cost 263 std::deque< const ast::Expr * > exprs; 264 const ArgPack * pack = this; 265 if ( expr ) { exprs.emplace_front( expr ); } 266 while ( pack->tupleStart == 0 ) { 267 pack = &packs[pack->parent]; 268 exprs.emplace_front( pack->expr ); 269 cost += pack->cost; 270 } 271 // reset pack to appropriate tuple 272 std::vector< ast::ptr< ast::Expr > > exprv( exprs.begin(), exprs.end() ); 273 expr = new ast::TupleExpr{ expr->location, std::move( exprv ) }; 274 tupleStart = pack->tupleStart - 1; 275 parent = pack->parent; 276 } 277 }; 278 279 /// Instantiates an argument to match a parameter, returns false if no matching results left 280 bool instantiateArgument( 281 const CodeLocation & location, 282 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args, 283 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab, 284 unsigned nTuples = 0 285 ) { 286 if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) { 287 // paramType is a TupleType -- group args into a TupleExpr 288 ++nTuples; 289 for ( const ast::Type * type : *tupleType ) { 290 // xxx - dropping initializer changes behaviour from previous, but seems correct 291 // ^^^ need to handle the case where a tuple has a default argument 292 if ( ! instantiateArgument( location, 293 type, nullptr, args, results, genStart, symtab, nTuples ) ) return false; 294 nTuples = 0; 295 } 296 // re-constitute tuples for final generation 297 for ( auto i = genStart; i < results.size(); ++i ) { 298 results[i].endTuple( results ); 299 } 300 return true; 301 } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) { 302 // paramType is a ttype, consumes all remaining arguments 303 304 // completed tuples; will be spliced to end of results to finish 305 std::vector< ArgPack > finalResults{}; 306 307 // iterate until all results completed 308 std::size_t genEnd; 309 ++nTuples; 310 do { 311 genEnd = results.size(); 312 313 // add another argument to results 314 for ( std::size_t i = genStart; i < genEnd; ++i ) { 315 unsigned nextArg = results[i].nextArg; 316 317 // use next element of exploded tuple if present 318 if ( results[i].hasExpl() ) { 319 const ExplodedArg & expl = results[i].getExpl( args ); 320 321 unsigned nextExpl = results[i].nextExpl + 1; 322 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; } 323 324 results.emplace_back( 325 i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ), 326 copy( results[i].need ), copy( results[i].have ), 327 copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl, 328 results[i].explAlt ); 329 330 continue; 331 } 332 333 // finish result when out of arguments 334 if ( nextArg >= args.size() ) { 335 ArgPack newResult{ 336 results[i].env, results[i].need, results[i].have, results[i].open }; 337 newResult.nextArg = nextArg; 338 const ast::Type * argType = nullptr; 339 340 if ( nTuples > 0 || ! results[i].expr ) { 341 // first iteration or no expression to clone, 342 // push empty tuple expression 343 newResult.parent = i; 344 newResult.expr = new ast::TupleExpr( location, {} ); 345 argType = newResult.expr->result; 346 } else { 347 // clone result to collect tuple 348 newResult.parent = results[i].parent; 349 newResult.cost = results[i].cost; 350 newResult.tupleStart = results[i].tupleStart; 351 newResult.expr = results[i].expr; 352 argType = newResult.expr->result; 353 354 if ( results[i].tupleStart > 0 && Tuples::isTtype( argType ) ) { 355 // the case where a ttype value is passed directly is special, 356 // e.g. for argument forwarding purposes 357 // xxx - what if passing multiple arguments, last of which is 358 // ttype? 359 // xxx - what would happen if unify was changed so that unifying 360 // tuple 361 // types flattened both before unifying lists? then pass in 362 // TupleType (ttype) below. 363 --newResult.tupleStart; 364 } else { 365 // collapse leftover arguments into tuple 366 newResult.endTuple( results ); 367 argType = newResult.expr->result; 368 } 369 } 370 371 // check unification for ttype before adding to final 372 if ( 373 unify( 374 ttype, argType, newResult.env, newResult.need, newResult.have, 375 newResult.open, symtab ) 376 ) { 377 finalResults.emplace_back( std::move( newResult ) ); 378 } 379 380 continue; 381 } 382 383 // add each possible next argument 384 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) { 385 const ExplodedArg & expl = args[nextArg][j]; 386 387 // fresh copies of parent parameters for this iteration 388 ast::TypeEnvironment env = results[i].env; 389 ast::OpenVarSet open = results[i].open; 390 391 env.addActual( expl.env, open ); 392 393 // skip empty tuple arguments by (nearly) cloning parent into next gen 394 if ( expl.exprs.empty() ) { 395 results.emplace_back( 396 results[i], std::move( env ), copy( results[i].need ), 397 copy( results[i].have ), std::move( open ), nextArg + 1, expl.cost ); 398 399 continue; 400 } 401 402 // add new result 403 results.emplace_back( 404 i, expl.exprs.front(), std::move( env ), copy( results[i].need ), 405 copy( results[i].have ), std::move( open ), nextArg + 1, nTuples, 406 expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 407 } 408 } 409 410 // reset for next round 411 genStart = genEnd; 412 nTuples = 0; 413 } while ( genEnd != results.size() ); 414 415 // splice final results onto results 416 for ( std::size_t i = 0; i < finalResults.size(); ++i ) { 417 results.emplace_back( std::move( finalResults[i] ) ); 418 } 419 return ! finalResults.empty(); 420 } 421 422 // iterate each current subresult 423 std::size_t genEnd = results.size(); 424 for ( std::size_t i = genStart; i < genEnd; ++i ) { 425 unsigned nextArg = results[i].nextArg; 426 427 // use remainder of exploded tuple if present 428 if ( results[i].hasExpl() ) { 429 const ExplodedArg & expl = results[i].getExpl( args ); 430 const ast::Expr * expr = expl.exprs[ results[i].nextExpl ]; 431 432 ast::TypeEnvironment env = results[i].env; 433 ast::AssertionSet need = results[i].need, have = results[i].have; 434 ast::OpenVarSet open = results[i].open; 435 436 const ast::Type * argType = expr->result; 437 438 PRINT( 439 std::cerr << "param type is "; 440 ast::print( std::cerr, paramType ); 441 std::cerr << std::endl << "arg type is "; 442 ast::print( std::cerr, argType ); 443 std::cerr << std::endl; 444 ) 445 446 if ( unify( paramType, argType, env, need, have, open, symtab ) ) { 447 unsigned nextExpl = results[i].nextExpl + 1; 448 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; } 449 450 results.emplace_back( 451 i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ), nextArg, 452 nTuples, Cost::zero, nextExpl, results[i].explAlt ); 453 } 454 455 continue; 456 } 457 458 // use default initializers if out of arguments 459 if ( nextArg >= args.size() ) { 460 if ( const ast::ConstantExpr * cnst = getDefaultValue( init ) ) { 461 ast::TypeEnvironment env = results[i].env; 462 ast::AssertionSet need = results[i].need, have = results[i].have; 463 ast::OpenVarSet open = results[i].open; 464 465 if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) { 466 results.emplace_back( 467 i, new ast::DefaultArgExpr{ cnst->location, cnst }, std::move( env ), 468 std::move( need ), std::move( have ), std::move( open ), nextArg, nTuples ); 469 } 470 } 471 472 continue; 473 } 474 475 // Check each possible next argument 476 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) { 477 const ExplodedArg & expl = args[nextArg][j]; 478 479 // fresh copies of parent parameters for this iteration 480 ast::TypeEnvironment env = results[i].env; 481 ast::AssertionSet need = results[i].need, have = results[i].have; 482 ast::OpenVarSet open = results[i].open; 483 484 env.addActual( expl.env, open ); 485 486 // skip empty tuple arguments by (nearly) cloning parent into next gen 487 if ( expl.exprs.empty() ) { 488 results.emplace_back( 489 results[i], std::move( env ), std::move( need ), std::move( have ), std::move( open ), 490 nextArg + 1, expl.cost ); 491 492 continue; 493 } 494 495 // consider only first exploded arg 496 const ast::Expr * expr = expl.exprs.front(); 497 const ast::Type * argType = expr->result; 498 499 PRINT( 500 std::cerr << "param type is "; 501 ast::print( std::cerr, paramType ); 502 std::cerr << std::endl << "arg type is "; 503 ast::print( std::cerr, argType ); 504 std::cerr << std::endl; 505 ) 506 507 // attempt to unify types 508 if ( unify( paramType, argType, env, need, have, open, symtab ) ) { 509 // add new result 510 results.emplace_back( 511 i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ), 512 nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 513 } 514 } 515 } 516 517 // reset for next parameter 518 genStart = genEnd; 519 520 return genEnd != results.size(); // were any new results added? 521 } 522 523 /// Generate a cast expression from `arg` to `toType` 524 const ast::Expr * restructureCast( 525 ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast 526 ) { 527 if ( 528 arg->result->size() > 1 529 && ! toType->isVoid() 530 && ! dynamic_cast< const ast::ReferenceType * >( toType ) 531 ) { 532 // Argument is a tuple and the target type is neither void nor a reference. Cast each 533 // member of the tuple to its corresponding target type, producing the tuple of those 534 // cast expressions. If there are more components of the tuple than components in the 535 // target type, then excess components do not come out in the result expression (but 536 // UniqueExpr ensures that the side effects will still be produced) 537 if ( Tuples::maybeImpureIgnoreUnique( arg ) ) { 538 // expressions which may contain side effects require a single unique instance of 539 // the expression 540 arg = new ast::UniqueExpr{ arg->location, arg }; 541 } 542 std::vector< ast::ptr< ast::Expr > > components; 543 for ( unsigned i = 0; i < toType->size(); ++i ) { 544 // cast each component 545 ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i }; 546 components.emplace_back( 547 restructureCast( idx, toType->getComponent( i ), isGenerated ) ); 548 } 549 return new ast::TupleExpr{ arg->location, std::move( components ) }; 550 } else { 551 // handle normally 552 return new ast::CastExpr{ arg->location, arg, toType, isGenerated }; 553 } 554 } 555 556 /// Gets the name from an untyped member expression (must be NameExpr) 557 const std::string & getMemberName( const ast::UntypedMemberExpr * memberExpr ) { 558 if ( memberExpr->member.as< ast::ConstantExpr >() ) { 559 SemanticError( memberExpr, "Indexed access to struct fields unsupported: " ); 560 } 561 562 return memberExpr->member.strict_as< ast::NameExpr >()->name; 563 } 564 565 /// Actually visits expressions to find their candidate interpretations 566 class Finder final : public ast::WithShortCircuiting { 567 const ResolveContext & context; 568 const ast::SymbolTable & symtab; 569 public: 570 // static size_t traceId; 571 CandidateFinder & selfFinder; 572 CandidateList & candidates; 573 const ast::TypeEnvironment & tenv; 574 ast::ptr< ast::Type > & targetType; 575 576 enum Errors { 577 NotFound, 578 NoMatch, 579 ArgsToFew, 580 ArgsToMany, 581 RetsToFew, 582 RetsToMany, 583 NoReason 584 }; 585 586 struct { 587 Errors code = NotFound; 588 } reason; 589 590 Finder( CandidateFinder & f ) 591 : context( f.context ), symtab( context.symtab ), selfFinder( f ), 592 candidates( f.candidates ), tenv( f.env ), targetType( f.targetType ) {} 593 594 void previsit( const ast::Node * ) { visit_children = false; } 595 596 /// Convenience to add candidate to list 597 template<typename... Args> 598 void addCandidate( Args &&... args ) { 599 candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } ); 600 reason.code = NoReason; 601 } 602 603 void postvisit( const ast::ApplicationExpr * applicationExpr ) { 604 addCandidate( applicationExpr, tenv ); 605 } 606 607 /// Set up candidate assertions for inference 608 void inferParameters( CandidateRef & newCand, CandidateList & out ); 609 610 /// Completes a function candidate with arguments located 611 void validateFunctionCandidate( 612 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 613 CandidateList & out ); 614 615 /// Builds a list of candidates for a function, storing them in out 616 void makeFunctionCandidates( 617 const CodeLocation & location, 618 const CandidateRef & func, const ast::FunctionType * funcType, 619 const ExplodedArgs_new & args, CandidateList & out ); 620 621 /// Adds implicit struct-conversions to the alternative list 622 void addAnonConversions( const CandidateRef & cand ); 623 624 /// Adds aggregate member interpretations 625 void addAggMembers( 626 const ast::BaseInstType * aggrInst, const ast::Expr * expr, 627 const Candidate & cand, const Cost & addedCost, const std::string & name 628 ); 629 630 /// Adds tuple member interpretations 631 void addTupleMembers( 632 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 633 const Cost & addedCost, const ast::Expr * member 634 ); 635 636 /// true if expression is an lvalue 637 static bool isLvalue( const ast::Expr * x ) { 638 return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() ); 639 } 640 641 void postvisit( const ast::UntypedExpr * untypedExpr ); 642 void postvisit( const ast::VariableExpr * variableExpr ); 643 void postvisit( const ast::ConstantExpr * constantExpr ); 644 void postvisit( const ast::SizeofExpr * sizeofExpr ); 645 void postvisit( const ast::AlignofExpr * alignofExpr ); 646 void postvisit( const ast::AddressExpr * addressExpr ); 647 void postvisit( const ast::LabelAddressExpr * labelExpr ); 648 void postvisit( const ast::CastExpr * castExpr ); 649 void postvisit( const ast::VirtualCastExpr * castExpr ); 650 void postvisit( const ast::KeywordCastExpr * castExpr ); 651 void postvisit( const ast::UntypedMemberExpr * memberExpr ); 652 void postvisit( const ast::MemberExpr * memberExpr ); 653 void postvisit( const ast::NameExpr * nameExpr ); 654 void postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ); 655 void postvisit( const ast::OffsetofExpr * offsetofExpr ); 656 void postvisit( const ast::OffsetPackExpr * offsetPackExpr ); 657 void postvisit( const ast::LogicalExpr * logicalExpr ); 658 void postvisit( const ast::ConditionalExpr * conditionalExpr ); 659 void postvisit( const ast::CommaExpr * commaExpr ); 660 void postvisit( const ast::ImplicitCopyCtorExpr * ctorExpr ); 661 void postvisit( const ast::ConstructorExpr * ctorExpr ); 662 void postvisit( const ast::RangeExpr * rangeExpr ); 663 void postvisit( const ast::UntypedTupleExpr * tupleExpr ); 664 void postvisit( const ast::TupleExpr * tupleExpr ); 665 void postvisit( const ast::TupleIndexExpr * tupleExpr ); 666 void postvisit( const ast::TupleAssignExpr * tupleExpr ); 667 void postvisit( const ast::UniqueExpr * unqExpr ); 668 void postvisit( const ast::StmtExpr * stmtExpr ); 669 void postvisit( const ast::UntypedInitExpr * initExpr ); 670 671 void postvisit( const ast::InitExpr * ) { 672 assertf( false, "CandidateFinder should never see a resolved InitExpr." ); 673 } 674 675 void postvisit( const ast::DeletedExpr * ) { 676 assertf( false, "CandidateFinder should never see a DeletedExpr." ); 677 } 678 679 void postvisit( const ast::GenericExpr * ) { 680 assertf( false, "_Generic is not yet supported." ); 681 } 682 }; 683 684 /// Set up candidate assertions for inference 685 void Finder::inferParameters( CandidateRef & newCand, CandidateList & out ) { 686 // Set need bindings for any unbound assertions 687 UniqueId crntResnSlot = 0; // matching ID for this expression's assertions 688 for ( auto & assn : newCand->need ) { 689 // skip already-matched assertions 690 if ( assn.second.resnSlot != 0 ) continue; 691 // assign slot for expression if needed 692 if ( crntResnSlot == 0 ) { crntResnSlot = ++globalResnSlot; } 693 // fix slot to assertion 694 assn.second.resnSlot = crntResnSlot; 695 } 696 // pair slot to expression 697 if ( crntResnSlot != 0 ) { 698 newCand->expr.get_and_mutate()->inferred.resnSlots().emplace_back( crntResnSlot ); 699 } 700 701 // add to output list; assertion satisfaction will occur later 702 out.emplace_back( newCand ); 703 } 704 705 /// Completes a function candidate with arguments located 706 void Finder::validateFunctionCandidate( 707 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 708 CandidateList & out 709 ) { 710 ast::ApplicationExpr * appExpr = 711 new ast::ApplicationExpr{ func->expr->location, func->expr }; 712 // sum cost and accumulate arguments 713 std::deque< const ast::Expr * > args; 714 Cost cost = func->cost; 715 const ArgPack * pack = &result; 716 while ( pack->expr ) { 717 args.emplace_front( pack->expr ); 718 cost += pack->cost; 719 pack = &results[pack->parent]; 720 } 721 std::vector< ast::ptr< ast::Expr > > vargs( args.begin(), args.end() ); 722 appExpr->args = std::move( vargs ); 723 // build and validate new candidate 724 auto newCand = 725 std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost ); 726 PRINT( 727 std::cerr << "instantiate function success: " << appExpr << std::endl; 728 std::cerr << "need assertions:" << std::endl; 729 ast::print( std::cerr, result.need, 2 ); 730 ) 731 inferParameters( newCand, out ); 732 } 733 734 /// Builds a list of candidates for a function, storing them in out 735 void Finder::makeFunctionCandidates( 736 const CodeLocation & location, 737 const CandidateRef & func, const ast::FunctionType * funcType, 738 const ExplodedArgs_new & args, CandidateList & out 739 ) { 740 ast::OpenVarSet funcOpen; 741 ast::AssertionSet funcNeed, funcHave; 742 ast::TypeEnvironment funcEnv{ func->env }; 743 makeUnifiableVars( funcType, funcOpen, funcNeed ); 744 // add all type variables as open variables now so that those not used in the 745 // parameter list are still considered open 746 funcEnv.add( funcType->forall ); 747 748 if ( targetType && ! targetType->isVoid() && ! funcType->returns.empty() ) { 749 // attempt to narrow based on expected target type 750 const ast::Type * returnType = funcType->returns.front(); 751 if ( ! unify( 752 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab ) 753 ) { 754 // unification failed, do not pursue this candidate 755 return; 756 } 757 } 758 759 // iteratively build matches, one parameter at a time 760 std::vector< ArgPack > results; 761 results.emplace_back( funcEnv, funcNeed, funcHave, funcOpen ); 762 std::size_t genStart = 0; 763 764 // xxx - how to handle default arg after change to ftype representation? 765 if (const ast::VariableExpr * varExpr = func->expr.as<ast::VariableExpr>()) { 766 if (const ast::FunctionDecl * funcDecl = varExpr->var.as<ast::FunctionDecl>()) { 767 // function may have default args only if directly calling by name 768 // must use types on candidate however, due to RenameVars substitution 769 auto nParams = funcType->params.size(); 770 771 for (size_t i=0; i<nParams; ++i) { 772 auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>(); 773 if (!instantiateArgument( location, 774 funcType->params[i], obj->init, args, results, genStart, symtab)) return; 775 } 776 goto endMatch; 777 } 778 } 779 for ( const auto & param : funcType->params ) { 780 // Try adding the arguments corresponding to the current parameter to the existing 781 // matches 782 // no default args for indirect calls 783 if ( ! instantiateArgument( location, 784 param, nullptr, args, results, genStart, symtab ) ) return; 785 } 786 787 endMatch: 788 if ( funcType->isVarArgs ) { 789 // append any unused arguments to vararg pack 790 std::size_t genEnd; 791 do { 792 genEnd = results.size(); 793 794 // iterate results 795 for ( std::size_t i = genStart; i < genEnd; ++i ) { 796 unsigned nextArg = results[i].nextArg; 797 798 // use remainder of exploded tuple if present 799 if ( results[i].hasExpl() ) { 800 const ExplodedArg & expl = results[i].getExpl( args ); 801 802 unsigned nextExpl = results[i].nextExpl + 1; 803 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; } 804 805 results.emplace_back( 806 i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ), 807 copy( results[i].need ), copy( results[i].have ), 808 copy( results[i].open ), nextArg, 0, Cost::zero, nextExpl, 809 results[i].explAlt ); 810 811 continue; 812 } 813 814 // finish result when out of arguments 815 if ( nextArg >= args.size() ) { 816 validateFunctionCandidate( func, results[i], results, out ); 817 818 continue; 819 } 820 821 // add each possible next argument 822 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) { 823 const ExplodedArg & expl = args[nextArg][j]; 824 825 // fresh copies of parent parameters for this iteration 826 ast::TypeEnvironment env = results[i].env; 827 ast::OpenVarSet open = results[i].open; 828 829 env.addActual( expl.env, open ); 830 831 // skip empty tuple arguments by (nearly) cloning parent into next gen 832 if ( expl.exprs.empty() ) { 833 results.emplace_back( 834 results[i], std::move( env ), copy( results[i].need ), 835 copy( results[i].have ), std::move( open ), nextArg + 1, 836 expl.cost ); 837 838 continue; 839 } 840 841 // add new result 842 results.emplace_back( 843 i, expl.exprs.front(), std::move( env ), copy( results[i].need ), 844 copy( results[i].have ), std::move( open ), nextArg + 1, 0, expl.cost, 845 expl.exprs.size() == 1 ? 0 : 1, j ); 846 } 847 } 848 849 genStart = genEnd; 850 } while( genEnd != results.size() ); 851 } else { 852 // filter out the results that don't use all the arguments 853 for ( std::size_t i = genStart; i < results.size(); ++i ) { 854 ArgPack & result = results[i]; 855 if ( ! result.hasExpl() && result.nextArg >= args.size() ) { 856 validateFunctionCandidate( func, result, results, out ); 857 } 858 } 859 } 860 } 861 862 /// Adds implicit struct-conversions to the alternative list 863 void Finder::addAnonConversions( const CandidateRef & cand ) { 864 // adds anonymous member interpretations whenever an aggregate value type is seen. 865 // it's okay for the aggregate expression to have reference type -- cast it to the 866 // base type to treat the aggregate as the referenced value 867 ast::ptr< ast::Expr > aggrExpr( cand->expr ); 868 ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result; 869 cand->env.apply( aggrType ); 870 871 if ( aggrType.as< ast::ReferenceType >() ) { 872 aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() }; 873 } 874 875 if ( auto structInst = aggrExpr->result.as< ast::StructInstType >() ) { 876 addAggMembers( structInst, aggrExpr, *cand, Cost::safe, "" ); 877 } else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) { 878 addAggMembers( unionInst, aggrExpr, *cand, Cost::safe, "" ); 879 } 880 } 881 882 /// Adds aggregate member interpretations 883 void Finder::addAggMembers( 884 const ast::BaseInstType * aggrInst, const ast::Expr * expr, 885 const Candidate & cand, const Cost & addedCost, const std::string & name 886 ) { 887 for ( const ast::Decl * decl : aggrInst->lookup( name ) ) { 888 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl ); 889 CandidateRef newCand = std::make_shared<Candidate>( 890 cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost ); 891 // add anonymous member interpretations whenever an aggregate value type is seen 892 // as a member expression 893 addAnonConversions( newCand ); 894 candidates.emplace_back( std::move( newCand ) ); 895 } 896 } 897 898 /// Adds tuple member interpretations 899 void Finder::addTupleMembers( 900 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 901 const Cost & addedCost, const ast::Expr * member 902 ) { 903 if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) { 904 // get the value of the constant expression as an int, must be between 0 and the 905 // length of the tuple to have meaning 906 long long val = constantExpr->intValue(); 907 if ( val >= 0 && (unsigned long long)val < tupleType->size() ) { 908 addCandidate( 909 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 910 addedCost ); 911 } 912 } 913 } 914 915 void Finder::postvisit( const ast::UntypedExpr * untypedExpr ) { 916 std::vector< CandidateFinder > argCandidates = 917 selfFinder.findSubExprs( untypedExpr->args ); 918 919 // take care of possible tuple assignments 920 // if not tuple assignment, handled as normal function call 921 Tuples::handleTupleAssignment( selfFinder, untypedExpr, argCandidates ); 922 923 CandidateFinder funcFinder( context, tenv ); 924 if (auto nameExpr = untypedExpr->func.as<ast::NameExpr>()) { 925 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name); 926 if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) { 927 assertf(!argCandidates.empty(), "special function call without argument"); 928 for (auto & firstArgCand: argCandidates[0]) { 929 ast::ptr<ast::Type> argType = firstArgCand->expr->result; 930 firstArgCand->env.apply(argType); 931 // strip references 932 // xxx - is this correct? 933 while (argType.as<ast::ReferenceType>()) argType = argType.as<ast::ReferenceType>()->base; 934 935 // convert 1-tuple to plain type 936 if (auto tuple = argType.as<ast::TupleType>()) { 937 if (tuple->size() == 1) { 938 argType = tuple->types[0]; 939 } 940 } 941 942 // if argType is an unbound type parameter, all special functions need to be searched. 943 if (isUnboundType(argType)) { 944 funcFinder.otypeKeys.clear(); 945 break; 946 } 947 948 if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer); 949 // else if (const ast::EnumInstType * enumInst = argType.as<ast::EnumInstType>()) { 950 // const ast::EnumDecl * enumDecl = enumInst->base; // Here 951 // if ( const ast::Type* enumType = enumDecl->base ) { 952 // // instance of enum (T) is a instance of type (T) 953 // funcFinder.otypeKeys.insert(Mangle::mangle(enumType, Mangle::NoGenericParams | Mangle::Type)); 954 // } else { 955 // // instance of an untyped enum is techically int 956 // funcFinder.otypeKeys.insert(Mangle::mangle(enumDecl, Mangle::NoGenericParams | Mangle::Type)); 957 // } 958 // } 959 else funcFinder.otypeKeys.insert(Mangle::mangle(argType, Mangle::NoGenericParams | Mangle::Type)); 960 } 961 } 962 } 963 // if candidates are already produced, do not fail 964 // xxx - is it possible that handleTupleAssignment and main finder both produce candidates? 965 // this means there exists ctor/assign functions with a tuple as first parameter. 966 ResolvMode mode = { 967 true, // adjust 968 !untypedExpr->func.as<ast::NameExpr>(), // prune if not calling by name 969 selfFinder.candidates.empty() // failfast if other options are not found 970 }; 971 funcFinder.find( untypedExpr->func, mode ); 972 // short-circuit if no candidates 973 // if ( funcFinder.candidates.empty() ) return; 974 975 reason.code = NoMatch; 976 977 // find function operators 978 ast::ptr< ast::Expr > opExpr = new ast::NameExpr{ untypedExpr->location, "?()" }; // ??? why not ?{} 979 CandidateFinder opFinder( context, tenv ); 980 // okay if there aren't any function operations 981 opFinder.find( opExpr, ResolvMode::withoutFailFast() ); 982 PRINT( 983 std::cerr << "known function ops:" << std::endl; 984 print( std::cerr, opFinder.candidates, 1 ); 985 ) 986 987 // pre-explode arguments 988 ExplodedArgs_new argExpansions; 989 for ( const CandidateFinder & args : argCandidates ) { 990 argExpansions.emplace_back(); 991 auto & argE = argExpansions.back(); 992 for ( const CandidateRef & arg : args ) { argE.emplace_back( *arg, symtab ); } 993 } 994 995 // Find function matches 996 CandidateList found; 997 SemanticErrorException errors; 998 for ( CandidateRef & func : funcFinder ) { 999 try { 1000 PRINT( 1001 std::cerr << "working on alternative:" << std::endl; 1002 print( std::cerr, *func, 2 ); 1003 ) 1004 1005 // check if the type is a pointer to function 1006 const ast::Type * funcResult = func->expr->result->stripReferences(); 1007 if ( auto pointer = dynamic_cast< const ast::PointerType * >( funcResult ) ) { 1008 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 1009 CandidateRef newFunc{ new Candidate{ *func } }; 1010 newFunc->expr = 1011 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); 1012 makeFunctionCandidates( untypedExpr->location, 1013 newFunc, function, argExpansions, found ); 1014 } 1015 } else if ( 1016 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 1017 ) { 1018 if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) { 1019 if ( auto function = clz->bound.as< ast::FunctionType >() ) { 1020 CandidateRef newFunc{ new Candidate{ *func } }; 1021 newFunc->expr = 1022 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); 1023 makeFunctionCandidates( untypedExpr->location, 1024 newFunc, function, argExpansions, found ); 1025 } 1026 } 1027 } 1028 } catch ( SemanticErrorException & e ) { errors.append( e ); } 1029 } 1030 1031 // Find matches on function operators `?()` 1032 if ( ! opFinder.candidates.empty() ) { 1033 // add exploded function alternatives to front of argument list 1034 std::vector< ExplodedArg > funcE; 1035 funcE.reserve( funcFinder.candidates.size() ); 1036 for ( const CandidateRef & func : funcFinder ) { 1037 funcE.emplace_back( *func, symtab ); 1038 } 1039 argExpansions.emplace_front( std::move( funcE ) ); 1040 1041 for ( const CandidateRef & op : opFinder ) { 1042 try { 1043 // check if type is pointer-to-function 1044 const ast::Type * opResult = op->expr->result->stripReferences(); 1045 if ( auto pointer = dynamic_cast< const ast::PointerType * >( opResult ) ) { 1046 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 1047 CandidateRef newOp{ new Candidate{ *op} }; 1048 newOp->expr = 1049 referenceToRvalueConversion( newOp->expr, newOp->cost ); 1050 makeFunctionCandidates( untypedExpr->location, 1051 newOp, function, argExpansions, found ); 1052 } 1053 } 1054 } catch ( SemanticErrorException & e ) { errors.append( e ); } 1055 } 1056 } 1057 1058 // Implement SFINAE; resolution errors are only errors if there aren't any non-error 1059 // candidates 1060 if ( found.empty() && ! errors.isEmpty() ) { throw errors; } 1061 1062 // Compute conversion costs 1063 for ( CandidateRef & withFunc : found ) { 1064 Cost cvtCost = computeApplicationConversionCost( withFunc, symtab ); 1065 1066 PRINT( 1067 auto appExpr = withFunc->expr.strict_as< ast::ApplicationExpr >(); 1068 auto pointer = appExpr->func->result.strict_as< ast::PointerType >(); 1069 auto function = pointer->base.strict_as< ast::FunctionType >(); 1070 1071 std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl; 1072 std::cerr << "parameters are:" << std::endl; 1073 ast::printAll( std::cerr, function->params, 2 ); 1074 std::cerr << "arguments are:" << std::endl; 1075 ast::printAll( std::cerr, appExpr->args, 2 ); 1076 std::cerr << "bindings are:" << std::endl; 1077 ast::print( std::cerr, withFunc->env, 2 ); 1078 std::cerr << "cost is: " << withFunc->cost << std::endl; 1079 std::cerr << "cost of conversion is:" << cvtCost << std::endl; 1080 ) 1081 1082 if ( cvtCost != Cost::infinity ) { 1083 withFunc->cvtCost = cvtCost; 1084 candidates.emplace_back( std::move( withFunc ) ); 1085 } 1086 } 1087 found = std::move( candidates ); 1088 1089 // use a new list so that candidates are not examined by addAnonConversions twice 1090 CandidateList winners = findMinCost( found ); 1091 promoteCvtCost( winners ); 1092 1093 // function may return a struct/union value, in which case we need to add candidates 1094 // for implicit conversions to each of the anonymous members, which must happen after 1095 // `findMinCost`, since anon conversions are never the cheapest 1096 for ( const CandidateRef & c : winners ) { 1097 addAnonConversions( c ); 1098 } 1099 spliceBegin( candidates, winners ); 1100 1101 if ( candidates.empty() && targetType && ! targetType->isVoid() ) { 1102 // If resolution is unsuccessful with a target type, try again without, since it 1103 // will sometimes succeed when it wouldn't with a target type binding. 1104 // For example: 1105 // forall( otype T ) T & ?[]( T *, ptrdiff_t ); 1106 // const char * x = "hello world"; 1107 // unsigned char ch = x[0]; 1108 // Fails with simple return type binding (xxx -- check this!) as follows: 1109 // * T is bound to unsigned char 1110 // * (x: const char *) is unified with unsigned char *, which fails 1111 // xxx -- fix this better 1112 targetType = nullptr; 1113 postvisit( untypedExpr ); 1114 } 1115 } 1116 1117 void Finder::postvisit( const ast::AddressExpr * addressExpr ) { 1118 CandidateFinder finder( context, tenv ); 1119 finder.find( addressExpr->arg ); 1120 1121 if ( finder.candidates.empty() ) return; 1122 1123 reason.code = NoMatch; 1124 1125 for ( CandidateRef & r : finder.candidates ) { 1126 if ( ! isLvalue( r->expr ) ) continue; 1127 addCandidate( *r, new ast::AddressExpr{ addressExpr->location, r->expr } ); 1128 } 1129 } 1130 1131 void Finder::postvisit( const ast::LabelAddressExpr * labelExpr ) { 1132 addCandidate( labelExpr, tenv ); 1133 } 1134 1135 void Finder::postvisit( const ast::CastExpr * castExpr ) { 1136 ast::ptr< ast::Type > toType = castExpr->result; 1137 assert( toType ); 1138 toType = resolveTypeof( toType, context ); 1139 toType = adjustExprType( toType, tenv, symtab ); 1140 1141 CandidateFinder finder( context, tenv, toType ); 1142 finder.find( castExpr->arg, ResolvMode::withAdjustment() ); 1143 1144 if ( !finder.candidates.empty() ) reason.code = NoMatch; 1145 1146 CandidateList matches; 1147 for ( CandidateRef & cand : finder.candidates ) { 1148 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have; 1149 ast::OpenVarSet open( cand->open ); 1150 1151 cand->env.extractOpenVars( open ); 1152 1153 // It is possible that a cast can throw away some values in a multiply-valued 1154 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the 1155 // subexpression results that are cast directly. The candidate is invalid if it 1156 // has fewer results than there are types to cast to. 1157 int discardedValues = cand->expr->result->size() - toType->size(); 1158 if ( discardedValues < 0 ) continue; 1159 1160 // unification run for side-effects 1161 unify( toType, cand->expr->result, cand->env, need, have, open, symtab ); 1162 Cost thisCost = 1163 (castExpr->isGenerated == ast::GeneratedFlag::GeneratedCast) 1164 ? conversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env ) 1165 : castCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env ); 1166 1167 PRINT( 1168 std::cerr << "working on cast with result: " << toType << std::endl; 1169 std::cerr << "and expr type: " << cand->expr->result << std::endl; 1170 std::cerr << "env: " << cand->env << std::endl; 1171 ) 1172 if ( thisCost != Cost::infinity ) { 1173 PRINT( 1174 std::cerr << "has finite cost." << std::endl; 1175 ) 1176 // count one safe conversion for each value that is thrown away 1177 thisCost.incSafe( discardedValues ); 1178 CandidateRef newCand = std::make_shared<Candidate>( 1179 restructureCast( cand->expr, toType, castExpr->isGenerated ), 1180 copy( cand->env ), std::move( open ), std::move( need ), cand->cost, 1181 cand->cost + thisCost ); 1182 inferParameters( newCand, matches ); 1183 } 1184 } 1185 1186 // select first on argument cost, then conversion cost 1187 CandidateList minArgCost = findMinCost( matches ); 1188 promoteCvtCost( minArgCost ); 1189 candidates = findMinCost( minArgCost ); 1190 } 1191 1192 void Finder::postvisit( const ast::VirtualCastExpr * castExpr ) { 1193 assertf( castExpr->result, "Implicit virtual cast targets not yet supported." ); 1194 CandidateFinder finder( context, tenv ); 1195 // don't prune here, all alternatives guaranteed to have same type 1196 finder.find( castExpr->arg, ResolvMode::withoutPrune() ); 1197 for ( CandidateRef & r : finder.candidates ) { 1198 addCandidate( 1199 *r, 1200 new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } ); 1201 } 1202 } 1203 1204 void Finder::postvisit( const ast::KeywordCastExpr * castExpr ) { 1205 const auto & loc = castExpr->location; 1206 assertf( castExpr->result, "Cast target should have been set in Validate." ); 1207 auto ref = castExpr->result.strict_as<ast::ReferenceType>(); 1208 auto inst = ref->base.strict_as<ast::StructInstType>(); 1209 auto target = inst->base.get(); 1210 1211 CandidateFinder finder( context, tenv ); 1212 1213 auto pick_alternatives = [target, this](CandidateList & found, bool expect_ref) { 1214 for (auto & cand : found) { 1215 const ast::Type * expr = cand->expr->result.get(); 1216 if (expect_ref) { 1217 auto res = dynamic_cast<const ast::ReferenceType*>(expr); 1218 if (!res) { continue; } 1219 expr = res->base.get(); 1220 } 1221 1222 if (auto insttype = dynamic_cast<const ast::TypeInstType*>(expr)) { 1223 auto td = cand->env.lookup(*insttype); 1224 if (!td) { continue; } 1225 expr = td->bound.get(); 1226 } 1227 1228 if (auto base = dynamic_cast<const ast::StructInstType*>(expr)) { 1229 if (base->base == target) { 1230 candidates.push_back( std::move(cand) ); 1231 reason.code = NoReason; 1232 } 1233 } 1234 } 1235 }; 1236 1237 try { 1238 // Attempt 1 : turn (thread&)X into (thread$&)X.__thrd 1239 // Clone is purely for memory management 1240 std::unique_ptr<const ast::Expr> tech1 { new ast::UntypedMemberExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.field), castExpr->arg) }; 1241 1242 // don't prune here, since it's guaranteed all alternatives will have the same type 1243 finder.find( tech1.get(), ResolvMode::withoutPrune() ); 1244 pick_alternatives(finder.candidates, false); 1245 1246 return; 1247 } catch(SemanticErrorException & ) {} 1248 1249 // Fallback : turn (thread&)X into (thread$&)get_thread(X) 1250 std::unique_ptr<const ast::Expr> fallback { ast::UntypedExpr::createDeref(loc, new ast::UntypedExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.getter), { castExpr->arg })) }; 1251 // don't prune here, since it's guaranteed all alternatives will have the same type 1252 finder.find( fallback.get(), ResolvMode::withoutPrune() ); 1253 1254 pick_alternatives(finder.candidates, true); 1255 1256 // Whatever happens here, we have no more fallbacks 1257 } 1258 1259 void Finder::postvisit( const ast::UntypedMemberExpr * memberExpr ) { 1260 CandidateFinder aggFinder( context, tenv ); 1261 aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() ); 1262 for ( CandidateRef & agg : aggFinder.candidates ) { 1263 // it's okay for the aggregate expression to have reference type -- cast it to the 1264 // base type to treat the aggregate as the referenced value 1265 Cost addedCost = Cost::zero; 1266 agg->expr = referenceToRvalueConversion( agg->expr, addedCost ); 1267 1268 // find member of the given type 1269 if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) { 1270 addAggMembers( 1271 structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1272 } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) { 1273 addAggMembers( 1274 unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1275 } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) { 1276 addTupleMembers( tupleType, agg->expr, *agg, addedCost, memberExpr->member ); 1277 } 1278 } 1279 } 1280 1281 void Finder::postvisit( const ast::MemberExpr * memberExpr ) { 1282 addCandidate( memberExpr, tenv ); 1283 } 1284 1285 void Finder::postvisit( const ast::NameExpr * nameExpr ) { 1286 std::vector< ast::SymbolTable::IdData > declList; 1287 if (!selfFinder.otypeKeys.empty()) { 1288 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name); 1289 assertf(kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS, "special lookup with non-special target: %s", nameExpr->name.c_str()); 1290 1291 for (auto & otypeKey: selfFinder.otypeKeys) { 1292 auto result = symtab.specialLookupId(kind, otypeKey); 1293 declList.insert(declList.end(), std::make_move_iterator(result.begin()), std::make_move_iterator(result.end())); 1294 } 1295 } else { 1296 declList = symtab.lookupId( nameExpr->name ); 1297 } 1298 PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; ) 1299 1300 if ( declList.empty() ) return; 1301 1302 reason.code = NoMatch; 1303 1304 for ( auto & data : declList ) { 1305 Cost cost = Cost::zero; 1306 ast::Expr * newExpr = data.combine( nameExpr->location, cost ); 1307 1308 CandidateRef newCand = std::make_shared<Candidate>( 1309 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 1310 cost ); 1311 1312 if (newCand->expr->env) { 1313 newCand->env.add(*newCand->expr->env); 1314 auto mutExpr = newCand->expr.get_and_mutate(); 1315 mutExpr->env = nullptr; 1316 newCand->expr = mutExpr; 1317 } 1318 1319 PRINT( 1320 std::cerr << "decl is "; 1321 ast::print( std::cerr, data.id ); 1322 std::cerr << std::endl; 1323 std::cerr << "newExpr is "; 1324 ast::print( std::cerr, newExpr ); 1325 std::cerr << std::endl; 1326 ) 1327 newCand->expr = ast::mutate_field( 1328 newCand->expr.get(), &ast::Expr::result, 1329 renameTyVars( newCand->expr->result ) ); 1330 // add anonymous member interpretations whenever an aggregate value type is seen 1331 // as a name expression 1332 addAnonConversions( newCand ); 1333 candidates.emplace_back( std::move( newCand ) ); 1334 } 1335 } 1336 1337 void Finder::postvisit( const ast::VariableExpr * variableExpr ) { 1338 // not sufficient to just pass `variableExpr` here, type might have changed since 1339 // creation 1340 addCandidate( 1341 new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv ); 1342 } 1343 1344 void Finder::postvisit( const ast::ConstantExpr * constantExpr ) { 1345 addCandidate( constantExpr, tenv ); 1346 } 1347 1348 void Finder::postvisit( const ast::SizeofExpr * sizeofExpr ) { 1349 if ( sizeofExpr->type ) { 1350 addCandidate( 1351 new ast::SizeofExpr{ 1352 sizeofExpr->location, resolveTypeof( sizeofExpr->type, context ) }, 1353 tenv ); 1354 } else { 1355 // find all candidates for the argument to sizeof 1356 CandidateFinder finder( context, tenv ); 1357 finder.find( sizeofExpr->expr ); 1358 // find the lowest-cost candidate, otherwise ambiguous 1359 CandidateList winners = findMinCost( finder.candidates ); 1360 if ( winners.size() != 1 ) { 1361 SemanticError( 1362 sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " ); 1363 } 1364 // return the lowest-cost candidate 1365 CandidateRef & choice = winners.front(); 1366 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost ); 1367 choice->cost = Cost::zero; 1368 addCandidate( *choice, new ast::SizeofExpr{ sizeofExpr->location, choice->expr } ); 1369 } 1370 } 1371 1372 void Finder::postvisit( const ast::AlignofExpr * alignofExpr ) { 1373 if ( alignofExpr->type ) { 1374 addCandidate( 1375 new ast::AlignofExpr{ 1376 alignofExpr->location, resolveTypeof( alignofExpr->type, context ) }, 1377 tenv ); 1378 } else { 1379 // find all candidates for the argument to alignof 1380 CandidateFinder finder( context, tenv ); 1381 finder.find( alignofExpr->expr ); 1382 // find the lowest-cost candidate, otherwise ambiguous 1383 CandidateList winners = findMinCost( finder.candidates ); 1384 if ( winners.size() != 1 ) { 1385 SemanticError( 1386 alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " ); 1387 } 1388 // return the lowest-cost candidate 1389 CandidateRef & choice = winners.front(); 1390 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost ); 1391 choice->cost = Cost::zero; 1392 addCandidate( 1393 *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } ); 1394 } 1395 } 1396 1397 void Finder::postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ) { 1398 const ast::BaseInstType * aggInst; 1399 if (( aggInst = offsetofExpr->type.as< ast::StructInstType >() )) ; 1400 else if (( aggInst = offsetofExpr->type.as< ast::UnionInstType >() )) ; 1401 else return; 1402 1403 for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) { 1404 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member ); 1405 addCandidate( 1406 new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv ); 1407 } 1408 } 1409 1410 void Finder::postvisit( const ast::OffsetofExpr * offsetofExpr ) { 1411 addCandidate( offsetofExpr, tenv ); 1412 } 1413 1414 void Finder::postvisit( const ast::OffsetPackExpr * offsetPackExpr ) { 1415 addCandidate( offsetPackExpr, tenv ); 1416 } 1417 1418 void Finder::postvisit( const ast::LogicalExpr * logicalExpr ) { 1419 CandidateFinder finder1( context, tenv ); 1420 finder1.find( logicalExpr->arg1, ResolvMode::withAdjustment() ); 1421 if ( finder1.candidates.empty() ) return; 1422 1423 CandidateFinder finder2( context, tenv ); 1424 finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() ); 1425 if ( finder2.candidates.empty() ) return; 1426 1427 reason.code = NoMatch; 1428 1429 for ( const CandidateRef & r1 : finder1.candidates ) { 1430 for ( const CandidateRef & r2 : finder2.candidates ) { 1431 ast::TypeEnvironment env{ r1->env }; 1432 env.simpleCombine( r2->env ); 1433 ast::OpenVarSet open{ r1->open }; 1434 mergeOpenVars( open, r2->open ); 1435 ast::AssertionSet need; 1436 mergeAssertionSet( need, r1->need ); 1437 mergeAssertionSet( need, r2->need ); 1438 1439 addCandidate( 1440 new ast::LogicalExpr{ 1441 logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd }, 1442 std::move( env ), std::move( open ), std::move( need ), r1->cost + r2->cost ); 1443 } 1444 } 1445 } 1446 1447 void Finder::postvisit( const ast::ConditionalExpr * conditionalExpr ) { 1448 // candidates for condition 1449 CandidateFinder finder1( context, tenv ); 1450 finder1.find( conditionalExpr->arg1, ResolvMode::withAdjustment() ); 1451 if ( finder1.candidates.empty() ) return; 1452 1453 // candidates for true result 1454 CandidateFinder finder2( context, tenv ); 1455 finder2.find( conditionalExpr->arg2, ResolvMode::withAdjustment() ); 1456 if ( finder2.candidates.empty() ) return; 1457 1458 // candidates for false result 1459 CandidateFinder finder3( context, tenv ); 1460 finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() ); 1461 if ( finder3.candidates.empty() ) return; 1462 1463 reason.code = NoMatch; 1464 1465 for ( const CandidateRef & r1 : finder1.candidates ) { 1466 for ( const CandidateRef & r2 : finder2.candidates ) { 1467 for ( const CandidateRef & r3 : finder3.candidates ) { 1468 ast::TypeEnvironment env{ r1->env }; 1469 env.simpleCombine( r2->env ); 1470 env.simpleCombine( r3->env ); 1471 ast::OpenVarSet open{ r1->open }; 1472 mergeOpenVars( open, r2->open ); 1473 mergeOpenVars( open, r3->open ); 1474 ast::AssertionSet need; 1475 mergeAssertionSet( need, r1->need ); 1476 mergeAssertionSet( need, r2->need ); 1477 mergeAssertionSet( need, r3->need ); 1478 ast::AssertionSet have; 1479 1480 // unify true and false results, then infer parameters to produce new 1481 // candidates 1482 ast::ptr< ast::Type > common; 1483 if ( 1484 unify( 1485 r2->expr->result, r3->expr->result, env, need, have, open, symtab, 1486 common ) 1487 ) { 1488 // generate typed expression 1489 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 1490 conditionalExpr->location, r1->expr, r2->expr, r3->expr }; 1491 newExpr->result = common ? common : r2->expr->result; 1492 // convert both options to result type 1493 Cost cost = r1->cost + r2->cost + r3->cost; 1494 newExpr->arg2 = computeExpressionConversionCost( 1495 newExpr->arg2, newExpr->result, symtab, env, cost ); 1496 newExpr->arg3 = computeExpressionConversionCost( 1497 newExpr->arg3, newExpr->result, symtab, env, cost ); 1498 // output candidate 1499 CandidateRef newCand = std::make_shared<Candidate>( 1500 newExpr, std::move( env ), std::move( open ), std::move( need ), cost ); 1501 inferParameters( newCand, candidates ); 1502 } 1503 } 1504 } 1505 } 1506 } 1507 1508 void Finder::postvisit( const ast::CommaExpr * commaExpr ) { 1509 ast::TypeEnvironment env{ tenv }; 1510 ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, context, env ); 1511 1512 CandidateFinder finder2( context, env ); 1513 finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() ); 1514 1515 for ( const CandidateRef & r2 : finder2.candidates ) { 1516 addCandidate( *r2, new ast::CommaExpr{ commaExpr->location, arg1, r2->expr } ); 1517 } 1518 } 1519 1520 void Finder::postvisit( const ast::ImplicitCopyCtorExpr * ctorExpr ) { 1521 addCandidate( ctorExpr, tenv ); 1522 } 1523 1524 void Finder::postvisit( const ast::ConstructorExpr * ctorExpr ) { 1525 CandidateFinder finder( context, tenv ); 1526 finder.find( ctorExpr->callExpr, ResolvMode::withoutPrune() ); 1527 for ( CandidateRef & r : finder.candidates ) { 1528 addCandidate( *r, new ast::ConstructorExpr{ ctorExpr->location, r->expr } ); 1529 } 1530 } 1531 1532 void Finder::postvisit( const ast::RangeExpr * rangeExpr ) { 1533 // resolve low and high, accept candidates where low and high types unify 1534 CandidateFinder finder1( context, tenv ); 1535 finder1.find( rangeExpr->low, ResolvMode::withAdjustment() ); 1536 if ( finder1.candidates.empty() ) return; 1537 1538 CandidateFinder finder2( context, tenv ); 1539 finder2.find( rangeExpr->high, ResolvMode::withAdjustment() ); 1540 if ( finder2.candidates.empty() ) return; 1541 1542 reason.code = NoMatch; 1543 1544 for ( const CandidateRef & r1 : finder1.candidates ) { 1545 for ( const CandidateRef & r2 : finder2.candidates ) { 1546 ast::TypeEnvironment env{ r1->env }; 1547 env.simpleCombine( r2->env ); 1548 ast::OpenVarSet open{ r1->open }; 1549 mergeOpenVars( open, r2->open ); 1550 ast::AssertionSet need; 1551 mergeAssertionSet( need, r1->need ); 1552 mergeAssertionSet( need, r2->need ); 1553 ast::AssertionSet have; 1554 1555 ast::ptr< ast::Type > common; 1556 if ( 1557 unify( 1558 r1->expr->result, r2->expr->result, env, need, have, open, symtab, 1559 common ) 1560 ) { 1561 // generate new expression 1562 ast::RangeExpr * newExpr = 1563 new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr }; 1564 newExpr->result = common ? common : r1->expr->result; 1565 // add candidate 1566 CandidateRef newCand = std::make_shared<Candidate>( 1567 newExpr, std::move( env ), std::move( open ), std::move( need ), 1568 r1->cost + r2->cost ); 1569 inferParameters( newCand, candidates ); 1570 } 1571 } 1572 } 1573 } 1574 1575 void Finder::postvisit( const ast::UntypedTupleExpr * tupleExpr ) { 1576 std::vector< CandidateFinder > subCandidates = 1577 selfFinder.findSubExprs( tupleExpr->exprs ); 1578 std::vector< CandidateList > possibilities; 1579 combos( subCandidates.begin(), subCandidates.end(), back_inserter( possibilities ) ); 1580 1581 for ( const CandidateList & subs : possibilities ) { 1582 std::vector< ast::ptr< ast::Expr > > exprs; 1583 exprs.reserve( subs.size() ); 1584 for ( const CandidateRef & sub : subs ) { exprs.emplace_back( sub->expr ); } 1585 1586 ast::TypeEnvironment env; 1587 ast::OpenVarSet open; 1588 ast::AssertionSet need; 1589 for ( const CandidateRef & sub : subs ) { 1590 env.simpleCombine( sub->env ); 1591 mergeOpenVars( open, sub->open ); 1592 mergeAssertionSet( need, sub->need ); 1593 } 1594 1595 addCandidate( 1596 new ast::TupleExpr{ tupleExpr->location, std::move( exprs ) }, 1597 std::move( env ), std::move( open ), std::move( need ), sumCost( subs ) ); 1598 } 1599 } 1600 1601 void Finder::postvisit( const ast::TupleExpr * tupleExpr ) { 1602 addCandidate( tupleExpr, tenv ); 1603 } 1604 1605 void Finder::postvisit( const ast::TupleIndexExpr * tupleExpr ) { 1606 addCandidate( tupleExpr, tenv ); 1607 } 1608 1609 void Finder::postvisit( const ast::TupleAssignExpr * tupleExpr ) { 1610 addCandidate( tupleExpr, tenv ); 1611 } 1612 1613 void Finder::postvisit( const ast::UniqueExpr * unqExpr ) { 1614 CandidateFinder finder( context, tenv ); 1615 finder.find( unqExpr->expr, ResolvMode::withAdjustment() ); 1616 for ( CandidateRef & r : finder.candidates ) { 1617 // ensure that the the id is passed on so that the expressions are "linked" 1618 addCandidate( *r, new ast::UniqueExpr{ unqExpr->location, r->expr, unqExpr->id } ); 1619 } 1620 } 1621 1622 void Finder::postvisit( const ast::StmtExpr * stmtExpr ) { 1623 addCandidate( resolveStmtExpr( stmtExpr, context ), tenv ); 1624 } 1625 1626 void Finder::postvisit( const ast::UntypedInitExpr * initExpr ) { 1627 // handle each option like a cast 1628 CandidateList matches; 1629 PRINT( 1630 std::cerr << "untyped init expr: " << initExpr << std::endl; 1631 ) 1632 // O(n^2) checks of d-types with e-types 1633 for ( const ast::InitAlternative & initAlt : initExpr->initAlts ) { 1634 // calculate target type 1635 const ast::Type * toType = resolveTypeof( initAlt.type, context ); 1636 toType = adjustExprType( toType, tenv, symtab ); 1637 // The call to find must occur inside this loop, otherwise polymorphic return 1638 // types are not bound to the initialization type, since return type variables are 1639 // only open for the duration of resolving the UntypedExpr. 1640 CandidateFinder finder( context, tenv, toType ); 1641 finder.find( initExpr->expr, ResolvMode::withAdjustment() ); 1642 for ( CandidateRef & cand : finder.candidates ) { 1643 if (reason.code == NotFound) reason.code = NoMatch; 1644 1645 ast::TypeEnvironment env{ cand->env }; 1646 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have; 1647 ast::OpenVarSet open{ cand->open }; 1648 1649 PRINT( 1650 std::cerr << " @ " << toType << " " << initAlt.designation << std::endl; 1651 ) 1652 1653 // It is possible that a cast can throw away some values in a multiply-valued 1654 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of 1655 // the subexpression results that are cast directly. The candidate is invalid 1656 // if it has fewer results than there are types to cast to. 1657 int discardedValues = cand->expr->result->size() - toType->size(); 1658 if ( discardedValues < 0 ) continue; 1659 1660 // unification run for side-effects 1661 bool canUnify = unify( toType, cand->expr->result, env, need, have, open, symtab ); 1662 (void) canUnify; 1663 Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), 1664 symtab, env ); 1665 PRINT( 1666 Cost legacyCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(), 1667 symtab, env ); 1668 std::cerr << "Considering initialization:"; 1669 std::cerr << std::endl << " FROM: " << cand->expr->result << std::endl; 1670 std::cerr << std::endl << " TO: " << toType << std::endl; 1671 std::cerr << std::endl << " Unification " << (canUnify ? "succeeded" : "failed"); 1672 std::cerr << std::endl << " Legacy cost " << legacyCost; 1673 std::cerr << std::endl << " New cost " << thisCost; 1674 std::cerr << std::endl; 1675 ) 1676 if ( thisCost != Cost::infinity ) { 1677 // count one safe conversion for each value that is thrown away 1678 thisCost.incSafe( discardedValues ); 1679 CandidateRef newCand = std::make_shared<Candidate>( 1680 new ast::InitExpr{ 1681 initExpr->location, restructureCast( cand->expr, toType ), 1682 initAlt.designation }, 1683 std::move(env), std::move( open ), std::move( need ), cand->cost, thisCost ); 1684 inferParameters( newCand, matches ); 1685 } 1686 } 1687 } 1688 1689 // select first on argument cost, then conversion cost 1690 CandidateList minArgCost = findMinCost( matches ); 1691 promoteCvtCost( minArgCost ); 1692 candidates = findMinCost( minArgCost ); 1693 } 1694 1695 // size_t Finder::traceId = Stats::Heap::new_stacktrace_id("Finder"); 1696 /// Prunes a list of candidates down to those that have the minimum conversion cost for a given 1697 /// return type. Skips ambiguous candidates. 1698 1699 } // anonymous namespace 1700 1701 bool CandidateFinder::pruneCandidates( CandidateList & candidates, CandidateList & out, std::vector<std::string> & errors ) { 1702 struct PruneStruct { 1703 CandidateRef candidate; 1704 bool ambiguous; 1705 1706 PruneStruct() = default; 1707 PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {} 1708 }; 1709 1710 // find lowest-cost candidate for each type 1711 std::unordered_map< std::string, PruneStruct > selected; 1712 // attempt to skip satisfyAssertions on more expensive alternatives if better options have been found 1713 std::sort(candidates.begin(), candidates.end(), [](const CandidateRef & x, const CandidateRef & y){return x->cost < y->cost;}); 1714 for ( CandidateRef & candidate : candidates ) { 1715 std::string mangleName; 1716 { 1717 ast::ptr< ast::Type > newType = candidate->expr->result; 1718 assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get()); 1719 candidate->env.apply( newType ); 1720 mangleName = Mangle::mangle( newType ); 1721 } 1722 1723 auto found = selected.find( mangleName ); 1724 if (found != selected.end() && found->second.candidate->cost < candidate->cost) { 1725 PRINT( 1726 std::cerr << "cost " << candidate->cost << " loses to " 1727 << found->second.candidate->cost << std::endl; 1728 ) 1729 continue; 1730 } 1731 1732 // xxx - when do satisfyAssertions produce more than 1 result? 1733 // this should only happen when initial result type contains 1734 // unbound type parameters, then it should never be pruned by 1735 // the previous step, since renameTyVars guarantees the mangled name 1736 // is unique. 1737 CandidateList satisfied; 1738 bool needRecomputeKey = false; 1739 if (candidate->need.empty()) { 1740 satisfied.emplace_back(candidate); 1741 } 1742 else { 1743 satisfyAssertions(candidate, context.symtab, satisfied, errors); 1744 needRecomputeKey = true; 1745 } 1746 1747 for (auto & newCand : satisfied) { 1748 // recomputes type key, if satisfyAssertions changed it 1749 if (needRecomputeKey) 1750 { 1751 ast::ptr< ast::Type > newType = newCand->expr->result; 1752 assertf(newCand->expr->result, "Result of expression %p for candidate is null", newCand->expr.get()); 1753 newCand->env.apply( newType ); 1754 mangleName = Mangle::mangle( newType ); 1755 } 1756 auto found = selected.find( mangleName ); 1757 if ( found != selected.end() ) { 1758 if ( newCand->cost < found->second.candidate->cost ) { 1759 PRINT( 1760 std::cerr << "cost " << newCand->cost << " beats " 1761 << found->second.candidate->cost << std::endl; 1762 ) 1763 1764 found->second = PruneStruct{ newCand }; 1765 } else if ( newCand->cost == found->second.candidate->cost ) { 1766 // if one of the candidates contains a deleted identifier, can pick the other, 1767 // since deleted expressions should not be ambiguous if there is another option 1768 // that is at least as good 1769 if ( findDeletedExpr( newCand->expr ) ) { 1770 // do nothing 1771 PRINT( std::cerr << "candidate is deleted" << std::endl; ) 1772 } else if ( findDeletedExpr( found->second.candidate->expr ) ) { 1773 PRINT( std::cerr << "current is deleted" << std::endl; ) 1774 found->second = PruneStruct{ newCand }; 1775 } else { 1776 PRINT( std::cerr << "marking ambiguous" << std::endl; ) 1777 found->second.ambiguous = true; 1778 } 1779 } else { 1780 // xxx - can satisfyAssertions increase the cost? 1781 PRINT( 1782 std::cerr << "cost " << newCand->cost << " loses to " 1783 << found->second.candidate->cost << std::endl; 1784 ) 1785 } 1786 } else { 1787 selected.emplace_hint( found, mangleName, newCand ); 1788 } 1789 } 1790 } 1791 1792 // report unambiguous min-cost candidates 1793 // CandidateList out; 1794 for ( auto & target : selected ) { 1795 if ( target.second.ambiguous ) continue; 1796 1797 CandidateRef cand = target.second.candidate; 1798 1799 ast::ptr< ast::Type > newResult = cand->expr->result; 1800 cand->env.applyFree( newResult ); 1801 cand->expr = ast::mutate_field( 1802 cand->expr.get(), &ast::Expr::result, std::move( newResult ) ); 1803 1804 out.emplace_back( cand ); 1805 } 1806 // if everything is lost in satisfyAssertions, report the error 1807 return !selected.empty(); 1808 } 1809 1810 void CandidateFinder::find( const ast::Expr * expr, ResolvMode mode ) { 1811 // Find alternatives for expression 1812 ast::Pass<Finder> finder{ *this }; 1813 expr->accept( finder ); 1814 1815 if ( mode.failFast && candidates.empty() ) { 1816 switch(finder.core.reason.code) { 1817 case Finder::NotFound: 1818 { SemanticError( expr, "No alternatives for expression " ); break; } 1819 case Finder::NoMatch: 1820 { SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; } 1821 case Finder::ArgsToFew: 1822 case Finder::ArgsToMany: 1823 case Finder::RetsToFew: 1824 case Finder::RetsToMany: 1825 case Finder::NoReason: 1826 default: 1827 { SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); } 1828 } 1829 } 1830 1831 /* 1832 if ( mode.satisfyAssns || mode.prune ) { 1833 // trim candidates to just those where the assertions are satisfiable 1834 // - necessary pre-requisite to pruning 1835 CandidateList satisfied; 1836 std::vector< std::string > errors; 1837 for ( CandidateRef & candidate : candidates ) { 1838 satisfyAssertions( candidate, localSyms, satisfied, errors ); 1839 } 1840 1841 // fail early if none such 1842 if ( mode.failFast && satisfied.empty() ) { 1843 std::ostringstream stream; 1844 stream << "No alternatives with satisfiable assertions for " << expr << "\n"; 1845 for ( const auto& err : errors ) { 1846 stream << err; 1847 } 1848 SemanticError( expr->location, stream.str() ); 1849 } 1850 1851 // reset candidates 1852 candidates = move( satisfied ); 1853 } 1854 */ 1855 1856 if ( mode.prune ) { 1857 // trim candidates to single best one 1858 PRINT( 1859 std::cerr << "alternatives before prune:" << std::endl; 1860 print( std::cerr, candidates ); 1861 ) 1862 1863 CandidateList pruned; 1864 std::vector<std::string> errors; 1865 bool found = pruneCandidates( candidates, pruned, errors ); 1866 1867 if ( mode.failFast && pruned.empty() ) { 1868 std::ostringstream stream; 1869 if (found) { 1870 CandidateList winners = findMinCost( candidates ); 1871 stream << "Cannot choose between " << winners.size() << " alternatives for " 1872 "expression\n"; 1873 ast::print( stream, expr ); 1874 stream << " Alternatives are:\n"; 1875 print( stream, winners, 1 ); 1876 SemanticError( expr->location, stream.str() ); 1877 } 1878 else { 1879 stream << "No alternatives with satisfiable assertions for " << expr << "\n"; 1880 for ( const auto& err : errors ) { 1881 stream << err; 1882 } 1883 SemanticError( expr->location, stream.str() ); 1884 } 1885 } 1886 1887 auto oldsize = candidates.size(); 1888 candidates = std::move( pruned ); 1889 1890 PRINT( 1891 std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl; 1892 ) 1893 PRINT( 1894 std::cerr << "there are " << candidates.size() << " alternatives after elimination" 1895 << std::endl; 1896 ) 1897 } 1898 1899 // adjust types after pruning so that types substituted by pruneAlternatives are correctly 1900 // adjusted 1901 if ( mode.adjust ) { 1902 for ( CandidateRef & r : candidates ) { 1903 r->expr = ast::mutate_field( 1904 r->expr.get(), &ast::Expr::result, 1905 adjustExprType( r->expr->result, r->env, context.symtab ) ); 1906 } 1907 } 1908 1909 // Central location to handle gcc extension keyword, etc. for all expressions 1910 for ( CandidateRef & r : candidates ) { 1911 if ( r->expr->extension != expr->extension ) { 1912 r->expr.get_and_mutate()->extension = expr->extension; 1913 } 1914 } 1915 } 1916 1917 std::vector< CandidateFinder > CandidateFinder::findSubExprs( 1918 const std::vector< ast::ptr< ast::Expr > > & xs 1919 ) { 1920 std::vector< CandidateFinder > out; 1921 1922 for ( const auto & x : xs ) { 1923 out.emplace_back( context, env ); 1924 out.back().find( x, ResolvMode::withAdjustment() ); 1925 1926 PRINT( 1927 std::cerr << "findSubExprs" << std::endl; 1928 print( std::cerr, out.back().candidates ); 1929 ) 1930 } 1931 1932 return out; 1933 } 1934 57 1935 const ast::Expr * referenceToRvalueConversion( const ast::Expr * expr, Cost & cost ) { 58 1936 if ( expr->result.as< ast::ReferenceType >() ) { … … 64 1942 return expr; 65 1943 } 66 67 /// Unique identifier for matching expression resolutions to their requesting expression68 UniqueId globalResnSlot = 0;69 1944 70 1945 Cost computeConversionCost( … … 93 1968 } 94 1969 95 namespace {96 /// First index is which argument, second is which alternative, third is which exploded element97 using ExplodedArgs_new = std::deque< std::vector< ExplodedArg > >;98 99 /// Returns a list of alternatives with the minimum cost in the given list100 CandidateList findMinCost( const CandidateList & candidates ) {101 CandidateList out;102 Cost minCost = Cost::infinity;103 for ( const CandidateRef & r : candidates ) {104 if ( r->cost < minCost ) {105 minCost = r->cost;106 out.clear();107 out.emplace_back( r );108 } else if ( r->cost == minCost ) {109 out.emplace_back( r );110 }111 }112 return out;113 }114 115 /// Computes conversion cost for a given expression to a given type116 const ast::Expr * computeExpressionConversionCost(117 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost118 ) {119 Cost convCost = computeConversionCost(120 arg->result, paramType, arg->get_lvalue(), symtab, env );121 outCost += convCost;122 123 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires124 // conversion. Ignore poly cost for now, since this requires resolution of the cast to125 // infer parameters and this does not currently work for the reason stated below126 Cost tmpCost = convCost;127 tmpCost.incPoly( -tmpCost.get_polyCost() );128 if ( tmpCost != Cost::zero ) {129 ast::ptr< ast::Type > newType = paramType;130 env.apply( newType );131 return new ast::CastExpr{ arg, newType };132 133 // xxx - *should* be able to resolve this cast, but at the moment pointers are not134 // castable to zero_t, but are implicitly convertible. This is clearly inconsistent,135 // once this is fixed it should be possible to resolve the cast.136 // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable,137 // but it shouldn't be because this makes the conversion from DT* to DT* since138 // commontype(zero_t, DT*) is DT*, rather than nothing139 140 // CandidateFinder finder{ symtab, env };141 // finder.find( arg, ResolvMode::withAdjustment() );142 // assertf( finder.candidates.size() > 0,143 // "Somehow castable expression failed to find alternatives." );144 // assertf( finder.candidates.size() == 1,145 // "Somehow got multiple alternatives for known cast expression." );146 // return finder.candidates.front()->expr;147 }148 149 return arg;150 }151 152 /// Computes conversion cost for a given candidate153 Cost computeApplicationConversionCost(154 CandidateRef cand, const ast::SymbolTable & symtab155 ) {156 auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >();157 auto pointer = appExpr->func->result.strict_as< ast::PointerType >();158 auto function = pointer->base.strict_as< ast::FunctionType >();159 160 Cost convCost = Cost::zero;161 const auto & params = function->params;162 auto param = params.begin();163 auto & args = appExpr->args;164 165 for ( unsigned i = 0; i < args.size(); ++i ) {166 const ast::Type * argType = args[i]->result;167 PRINT(168 std::cerr << "arg expression:" << std::endl;169 ast::print( std::cerr, args[i], 2 );170 std::cerr << "--- results are" << std::endl;171 ast::print( std::cerr, argType, 2 );172 )173 174 if ( param == params.end() ) {175 if ( function->isVarArgs ) {176 convCost.incUnsafe();177 PRINT( std::cerr << "end of params with varargs function: inc unsafe: "178 << convCost << std::endl; ; )179 // convert reference-typed expressions into value-typed expressions180 cand->expr = ast::mutate_field_index(181 appExpr, &ast::ApplicationExpr::args, i,182 referenceToRvalueConversion( args[i], convCost ) );183 continue;184 } else return Cost::infinity;185 }186 187 if ( auto def = args[i].as< ast::DefaultArgExpr >() ) {188 // Default arguments should be free - don't include conversion cost.189 // Unwrap them here because they are not relevant to the rest of the system190 cand->expr = ast::mutate_field_index(191 appExpr, &ast::ApplicationExpr::args, i, def->expr );192 ++param;193 continue;194 }195 196 // mark conversion cost and also specialization cost of param type197 // const ast::Type * paramType = (*param)->get_type();198 cand->expr = ast::mutate_field_index(199 appExpr, &ast::ApplicationExpr::args, i,200 computeExpressionConversionCost(201 args[i], *param, symtab, cand->env, convCost ) );202 convCost.decSpec( specCost( *param ) );203 ++param; // can't be in for-loop update because of the continue204 }205 206 if ( param != params.end() ) return Cost::infinity;207 208 // specialization cost of return types can't be accounted for directly, it disables209 // otherwise-identical calls, like this example based on auto-newline in the I/O lib:210 //211 // forall(otype OS) {212 // void ?|?(OS&, int); // with newline213 // OS& ?|?(OS&, int); // no newline, always chosen due to more specialization214 // }215 216 // mark type variable and specialization cost of forall clause217 convCost.incVar( function->forall.size() );218 convCost.decSpec( function->assertions.size() );219 220 return convCost;221 }222 223 void makeUnifiableVars(224 const ast::FunctionType * type, ast::OpenVarSet & unifiableVars,225 ast::AssertionSet & need226 ) {227 for ( auto & tyvar : type->forall ) {228 unifiableVars[ *tyvar ] = ast::TypeData{ tyvar->base };229 }230 for ( auto & assn : type->assertions ) {231 need[ assn ].isUsed = true;232 }233 }234 235 /// Gets a default value from an initializer, nullptr if not present236 const ast::ConstantExpr * getDefaultValue( const ast::Init * init ) {237 if ( auto si = dynamic_cast< const ast::SingleInit * >( init ) ) {238 if ( auto ce = si->value.as< ast::CastExpr >() ) {239 return ce->arg.as< ast::ConstantExpr >();240 } else {241 return si->value.as< ast::ConstantExpr >();242 }243 }244 return nullptr;245 }246 247 /// State to iteratively build a match of parameter expressions to arguments248 struct ArgPack {249 std::size_t parent; ///< Index of parent pack250 ast::ptr< ast::Expr > expr; ///< The argument stored here251 Cost cost; ///< The cost of this argument252 ast::TypeEnvironment env; ///< Environment for this pack253 ast::AssertionSet need; ///< Assertions outstanding for this pack254 ast::AssertionSet have; ///< Assertions found for this pack255 ast::OpenVarSet open; ///< Open variables for this pack256 unsigned nextArg; ///< Index of next argument in arguments list257 unsigned tupleStart; ///< Number of tuples that start at this index258 unsigned nextExpl; ///< Index of next exploded element259 unsigned explAlt; ///< Index of alternative for nextExpl > 0260 261 ArgPack()262 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ),263 tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}264 265 ArgPack(266 const ast::TypeEnvironment & env, const ast::AssertionSet & need,267 const ast::AssertionSet & have, const ast::OpenVarSet & open )268 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ),269 open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}270 271 ArgPack(272 std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env,273 ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open,274 unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero,275 unsigned nextExpl = 0, unsigned explAlt = 0 )276 : parent(parent), expr( expr ), cost( cost ), env( std::move( env ) ), need( std::move( need ) ),277 have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ),278 nextExpl( nextExpl ), explAlt( explAlt ) {}279 280 ArgPack(281 const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need,282 ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added )283 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( std::move( env ) ),284 need( std::move( need ) ), have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ),285 tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {}286 287 /// true if this pack is in the middle of an exploded argument288 bool hasExpl() const { return nextExpl > 0; }289 290 /// Gets the list of exploded candidates for this pack291 const ExplodedArg & getExpl( const ExplodedArgs_new & args ) const {292 return args[ nextArg-1 ][ explAlt ];293 }294 295 /// Ends a tuple expression, consolidating the appropriate args296 void endTuple( const std::vector< ArgPack > & packs ) {297 // add all expressions in tuple to list, summing cost298 std::deque< const ast::Expr * > exprs;299 const ArgPack * pack = this;300 if ( expr ) { exprs.emplace_front( expr ); }301 while ( pack->tupleStart == 0 ) {302 pack = &packs[pack->parent];303 exprs.emplace_front( pack->expr );304 cost += pack->cost;305 }306 // reset pack to appropriate tuple307 std::vector< ast::ptr< ast::Expr > > exprv( exprs.begin(), exprs.end() );308 expr = new ast::TupleExpr{ expr->location, std::move( exprv ) };309 tupleStart = pack->tupleStart - 1;310 parent = pack->parent;311 }312 };313 314 /// Instantiates an argument to match a parameter, returns false if no matching results left315 bool instantiateArgument(316 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args,317 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab,318 unsigned nTuples = 0319 ) {320 if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) {321 // paramType is a TupleType -- group args into a TupleExpr322 ++nTuples;323 for ( const ast::Type * type : *tupleType ) {324 // xxx - dropping initializer changes behaviour from previous, but seems correct325 // ^^^ need to handle the case where a tuple has a default argument326 if ( ! instantiateArgument(327 type, nullptr, args, results, genStart, symtab, nTuples ) ) return false;328 nTuples = 0;329 }330 // re-constitute tuples for final generation331 for ( auto i = genStart; i < results.size(); ++i ) {332 results[i].endTuple( results );333 }334 return true;335 } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) {336 // paramType is a ttype, consumes all remaining arguments337 338 // completed tuples; will be spliced to end of results to finish339 std::vector< ArgPack > finalResults{};340 341 // iterate until all results completed342 std::size_t genEnd;343 ++nTuples;344 do {345 genEnd = results.size();346 347 // add another argument to results348 for ( std::size_t i = genStart; i < genEnd; ++i ) {349 unsigned nextArg = results[i].nextArg;350 351 // use next element of exploded tuple if present352 if ( results[i].hasExpl() ) {353 const ExplodedArg & expl = results[i].getExpl( args );354 355 unsigned nextExpl = results[i].nextExpl + 1;356 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }357 358 results.emplace_back(359 i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),360 copy( results[i].need ), copy( results[i].have ),361 copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl,362 results[i].explAlt );363 364 continue;365 }366 367 // finish result when out of arguments368 if ( nextArg >= args.size() ) {369 ArgPack newResult{370 results[i].env, results[i].need, results[i].have, results[i].open };371 newResult.nextArg = nextArg;372 const ast::Type * argType = nullptr;373 374 if ( nTuples > 0 || ! results[i].expr ) {375 // first iteration or no expression to clone,376 // push empty tuple expression377 newResult.parent = i;378 newResult.expr = new ast::TupleExpr{ CodeLocation{}, {} };379 argType = newResult.expr->result;380 } else {381 // clone result to collect tuple382 newResult.parent = results[i].parent;383 newResult.cost = results[i].cost;384 newResult.tupleStart = results[i].tupleStart;385 newResult.expr = results[i].expr;386 argType = newResult.expr->result;387 388 if ( results[i].tupleStart > 0 && Tuples::isTtype( argType ) ) {389 // the case where a ttype value is passed directly is special,390 // e.g. for argument forwarding purposes391 // xxx - what if passing multiple arguments, last of which is392 // ttype?393 // xxx - what would happen if unify was changed so that unifying394 // tuple395 // types flattened both before unifying lists? then pass in396 // TupleType (ttype) below.397 --newResult.tupleStart;398 } else {399 // collapse leftover arguments into tuple400 newResult.endTuple( results );401 argType = newResult.expr->result;402 }403 }404 405 // check unification for ttype before adding to final406 if (407 unify(408 ttype, argType, newResult.env, newResult.need, newResult.have,409 newResult.open, symtab )410 ) {411 finalResults.emplace_back( std::move( newResult ) );412 }413 414 continue;415 }416 417 // add each possible next argument418 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {419 const ExplodedArg & expl = args[nextArg][j];420 421 // fresh copies of parent parameters for this iteration422 ast::TypeEnvironment env = results[i].env;423 ast::OpenVarSet open = results[i].open;424 425 env.addActual( expl.env, open );426 427 // skip empty tuple arguments by (nearly) cloning parent into next gen428 if ( expl.exprs.empty() ) {429 results.emplace_back(430 results[i], std::move( env ), copy( results[i].need ),431 copy( results[i].have ), std::move( open ), nextArg + 1, expl.cost );432 433 continue;434 }435 436 // add new result437 results.emplace_back(438 i, expl.exprs.front(), std::move( env ), copy( results[i].need ),439 copy( results[i].have ), std::move( open ), nextArg + 1, nTuples,440 expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );441 }442 }443 444 // reset for next round445 genStart = genEnd;446 nTuples = 0;447 } while ( genEnd != results.size() );448 449 // splice final results onto results450 for ( std::size_t i = 0; i < finalResults.size(); ++i ) {451 results.emplace_back( std::move( finalResults[i] ) );452 }453 return ! finalResults.empty();454 }455 456 // iterate each current subresult457 std::size_t genEnd = results.size();458 for ( std::size_t i = genStart; i < genEnd; ++i ) {459 unsigned nextArg = results[i].nextArg;460 461 // use remainder of exploded tuple if present462 if ( results[i].hasExpl() ) {463 const ExplodedArg & expl = results[i].getExpl( args );464 const ast::Expr * expr = expl.exprs[ results[i].nextExpl ];465 466 ast::TypeEnvironment env = results[i].env;467 ast::AssertionSet need = results[i].need, have = results[i].have;468 ast::OpenVarSet open = results[i].open;469 470 const ast::Type * argType = expr->result;471 472 PRINT(473 std::cerr << "param type is ";474 ast::print( std::cerr, paramType );475 std::cerr << std::endl << "arg type is ";476 ast::print( std::cerr, argType );477 std::cerr << std::endl;478 )479 480 if ( unify( paramType, argType, env, need, have, open, symtab ) ) {481 unsigned nextExpl = results[i].nextExpl + 1;482 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }483 484 results.emplace_back(485 i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ), nextArg,486 nTuples, Cost::zero, nextExpl, results[i].explAlt );487 }488 489 continue;490 }491 492 // use default initializers if out of arguments493 if ( nextArg >= args.size() ) {494 if ( const ast::ConstantExpr * cnst = getDefaultValue( init ) ) {495 ast::TypeEnvironment env = results[i].env;496 ast::AssertionSet need = results[i].need, have = results[i].have;497 ast::OpenVarSet open = results[i].open;498 499 if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) {500 results.emplace_back(501 i, new ast::DefaultArgExpr{ cnst->location, cnst }, std::move( env ),502 std::move( need ), std::move( have ), std::move( open ), nextArg, nTuples );503 }504 }505 506 continue;507 }508 509 // Check each possible next argument510 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {511 const ExplodedArg & expl = args[nextArg][j];512 513 // fresh copies of parent parameters for this iteration514 ast::TypeEnvironment env = results[i].env;515 ast::AssertionSet need = results[i].need, have = results[i].have;516 ast::OpenVarSet open = results[i].open;517 518 env.addActual( expl.env, open );519 520 // skip empty tuple arguments by (nearly) cloning parent into next gen521 if ( expl.exprs.empty() ) {522 results.emplace_back(523 results[i], std::move( env ), std::move( need ), std::move( have ), std::move( open ),524 nextArg + 1, expl.cost );525 526 continue;527 }528 529 // consider only first exploded arg530 const ast::Expr * expr = expl.exprs.front();531 const ast::Type * argType = expr->result;532 533 PRINT(534 std::cerr << "param type is ";535 ast::print( std::cerr, paramType );536 std::cerr << std::endl << "arg type is ";537 ast::print( std::cerr, argType );538 std::cerr << std::endl;539 )540 541 // attempt to unify types542 if ( unify( paramType, argType, env, need, have, open, symtab ) ) {543 // add new result544 results.emplace_back(545 i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ),546 nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );547 }548 }549 }550 551 // reset for next parameter552 genStart = genEnd;553 554 return genEnd != results.size(); // were any new results added?555 }556 557 /// Generate a cast expression from `arg` to `toType`558 const ast::Expr * restructureCast(559 ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast560 ) {561 if (562 arg->result->size() > 1563 && ! toType->isVoid()564 && ! dynamic_cast< const ast::ReferenceType * >( toType )565 ) {566 // Argument is a tuple and the target type is neither void nor a reference. Cast each567 // member of the tuple to its corresponding target type, producing the tuple of those568 // cast expressions. If there are more components of the tuple than components in the569 // target type, then excess components do not come out in the result expression (but570 // UniqueExpr ensures that the side effects will still be produced)571 if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {572 // expressions which may contain side effects require a single unique instance of573 // the expression574 arg = new ast::UniqueExpr{ arg->location, arg };575 }576 std::vector< ast::ptr< ast::Expr > > components;577 for ( unsigned i = 0; i < toType->size(); ++i ) {578 // cast each component579 ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i };580 components.emplace_back(581 restructureCast( idx, toType->getComponent( i ), isGenerated ) );582 }583 return new ast::TupleExpr{ arg->location, std::move( components ) };584 } else {585 // handle normally586 return new ast::CastExpr{ arg->location, arg, toType, isGenerated };587 }588 }589 590 /// Gets the name from an untyped member expression (must be NameExpr)591 const std::string & getMemberName( const ast::UntypedMemberExpr * memberExpr ) {592 if ( memberExpr->member.as< ast::ConstantExpr >() ) {593 SemanticError( memberExpr, "Indexed access to struct fields unsupported: " );594 }595 596 return memberExpr->member.strict_as< ast::NameExpr >()->name;597 }598 599 /// Actually visits expressions to find their candidate interpretations600 class Finder final : public ast::WithShortCircuiting {601 const ResolveContext & context;602 const ast::SymbolTable & symtab;603 public:604 // static size_t traceId;605 CandidateFinder & selfFinder;606 CandidateList & candidates;607 const ast::TypeEnvironment & tenv;608 ast::ptr< ast::Type > & targetType;609 610 enum Errors {611 NotFound,612 NoMatch,613 ArgsToFew,614 ArgsToMany,615 RetsToFew,616 RetsToMany,617 NoReason618 };619 620 struct {621 Errors code = NotFound;622 } reason;623 624 Finder( CandidateFinder & f )625 : context( f.context ), symtab( context.symtab ), selfFinder( f ),626 candidates( f.candidates ), tenv( f.env ), targetType( f.targetType ) {}627 628 void previsit( const ast::Node * ) { visit_children = false; }629 630 /// Convenience to add candidate to list631 template<typename... Args>632 void addCandidate( Args &&... args ) {633 candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } );634 reason.code = NoReason;635 }636 637 void postvisit( const ast::ApplicationExpr * applicationExpr ) {638 addCandidate( applicationExpr, tenv );639 }640 641 /// Set up candidate assertions for inference642 void inferParameters( CandidateRef & newCand, CandidateList & out ) {643 // Set need bindings for any unbound assertions644 UniqueId crntResnSlot = 0; // matching ID for this expression's assertions645 for ( auto & assn : newCand->need ) {646 // skip already-matched assertions647 if ( assn.second.resnSlot != 0 ) continue;648 // assign slot for expression if needed649 if ( crntResnSlot == 0 ) { crntResnSlot = ++globalResnSlot; }650 // fix slot to assertion651 assn.second.resnSlot = crntResnSlot;652 }653 // pair slot to expression654 if ( crntResnSlot != 0 ) {655 newCand->expr.get_and_mutate()->inferred.resnSlots().emplace_back( crntResnSlot );656 }657 658 // add to output list; assertion satisfaction will occur later659 out.emplace_back( newCand );660 }661 662 /// Completes a function candidate with arguments located663 void validateFunctionCandidate(664 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results,665 CandidateList & out666 ) {667 ast::ApplicationExpr * appExpr =668 new ast::ApplicationExpr{ func->expr->location, func->expr };669 // sum cost and accumulate arguments670 std::deque< const ast::Expr * > args;671 Cost cost = func->cost;672 const ArgPack * pack = &result;673 while ( pack->expr ) {674 args.emplace_front( pack->expr );675 cost += pack->cost;676 pack = &results[pack->parent];677 }678 std::vector< ast::ptr< ast::Expr > > vargs( args.begin(), args.end() );679 appExpr->args = std::move( vargs );680 // build and validate new candidate681 auto newCand =682 std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost );683 PRINT(684 std::cerr << "instantiate function success: " << appExpr << std::endl;685 std::cerr << "need assertions:" << std::endl;686 ast::print( std::cerr, result.need, 2 );687 )688 inferParameters( newCand, out );689 }690 691 /// Builds a list of candidates for a function, storing them in out692 void makeFunctionCandidates(693 const CandidateRef & func, const ast::FunctionType * funcType,694 const ExplodedArgs_new & args, CandidateList & out695 ) {696 ast::OpenVarSet funcOpen;697 ast::AssertionSet funcNeed, funcHave;698 ast::TypeEnvironment funcEnv{ func->env };699 makeUnifiableVars( funcType, funcOpen, funcNeed );700 // add all type variables as open variables now so that those not used in the701 // parameter list are still considered open702 funcEnv.add( funcType->forall );703 704 if ( targetType && ! targetType->isVoid() && ! funcType->returns.empty() ) {705 // attempt to narrow based on expected target type706 const ast::Type * returnType = funcType->returns.front();707 if ( ! unify(708 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab )709 ) {710 // unification failed, do not pursue this candidate711 return;712 }713 }714 715 // iteratively build matches, one parameter at a time716 std::vector< ArgPack > results;717 results.emplace_back( funcEnv, funcNeed, funcHave, funcOpen );718 std::size_t genStart = 0;719 720 // xxx - how to handle default arg after change to ftype representation?721 if (const ast::VariableExpr * varExpr = func->expr.as<ast::VariableExpr>()) {722 if (const ast::FunctionDecl * funcDecl = varExpr->var.as<ast::FunctionDecl>()) {723 // function may have default args only if directly calling by name724 // must use types on candidate however, due to RenameVars substitution725 auto nParams = funcType->params.size();726 727 for (size_t i=0; i<nParams; ++i) {728 auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>();729 if (!instantiateArgument(730 funcType->params[i], obj->init, args, results, genStart, symtab)) return;731 }732 goto endMatch;733 }734 }735 for ( const auto & param : funcType->params ) {736 // Try adding the arguments corresponding to the current parameter to the existing737 // matches738 // no default args for indirect calls739 if ( ! instantiateArgument(740 param, nullptr, args, results, genStart, symtab ) ) return;741 }742 743 endMatch:744 if ( funcType->isVarArgs ) {745 // append any unused arguments to vararg pack746 std::size_t genEnd;747 do {748 genEnd = results.size();749 750 // iterate results751 for ( std::size_t i = genStart; i < genEnd; ++i ) {752 unsigned nextArg = results[i].nextArg;753 754 // use remainder of exploded tuple if present755 if ( results[i].hasExpl() ) {756 const ExplodedArg & expl = results[i].getExpl( args );757 758 unsigned nextExpl = results[i].nextExpl + 1;759 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }760 761 results.emplace_back(762 i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),763 copy( results[i].need ), copy( results[i].have ),764 copy( results[i].open ), nextArg, 0, Cost::zero, nextExpl,765 results[i].explAlt );766 767 continue;768 }769 770 // finish result when out of arguments771 if ( nextArg >= args.size() ) {772 validateFunctionCandidate( func, results[i], results, out );773 774 continue;775 }776 777 // add each possible next argument778 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {779 const ExplodedArg & expl = args[nextArg][j];780 781 // fresh copies of parent parameters for this iteration782 ast::TypeEnvironment env = results[i].env;783 ast::OpenVarSet open = results[i].open;784 785 env.addActual( expl.env, open );786 787 // skip empty tuple arguments by (nearly) cloning parent into next gen788 if ( expl.exprs.empty() ) {789 results.emplace_back(790 results[i], std::move( env ), copy( results[i].need ),791 copy( results[i].have ), std::move( open ), nextArg + 1,792 expl.cost );793 794 continue;795 }796 797 // add new result798 results.emplace_back(799 i, expl.exprs.front(), std::move( env ), copy( results[i].need ),800 copy( results[i].have ), std::move( open ), nextArg + 1, 0, expl.cost,801 expl.exprs.size() == 1 ? 0 : 1, j );802 }803 }804 805 genStart = genEnd;806 } while( genEnd != results.size() );807 } else {808 // filter out the results that don't use all the arguments809 for ( std::size_t i = genStart; i < results.size(); ++i ) {810 ArgPack & result = results[i];811 if ( ! result.hasExpl() && result.nextArg >= args.size() ) {812 validateFunctionCandidate( func, result, results, out );813 }814 }815 }816 }817 818 /// Adds implicit struct-conversions to the alternative list819 void addAnonConversions( const CandidateRef & cand ) {820 // adds anonymous member interpretations whenever an aggregate value type is seen.821 // it's okay for the aggregate expression to have reference type -- cast it to the822 // base type to treat the aggregate as the referenced value823 ast::ptr< ast::Expr > aggrExpr( cand->expr );824 ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result;825 cand->env.apply( aggrType );826 827 if ( aggrType.as< ast::ReferenceType >() ) {828 aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() };829 }830 831 if ( auto structInst = aggrExpr->result.as< ast::StructInstType >() ) {832 addAggMembers( structInst, aggrExpr, *cand, Cost::safe, "" );833 } else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) {834 addAggMembers( unionInst, aggrExpr, *cand, Cost::safe, "" );835 }836 }837 838 /// Adds aggregate member interpretations839 void addAggMembers(840 const ast::BaseInstType * aggrInst, const ast::Expr * expr,841 const Candidate & cand, const Cost & addedCost, const std::string & name842 ) {843 for ( const ast::Decl * decl : aggrInst->lookup( name ) ) {844 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl );845 CandidateRef newCand = std::make_shared<Candidate>(846 cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost );847 // add anonymous member interpretations whenever an aggregate value type is seen848 // as a member expression849 addAnonConversions( newCand );850 candidates.emplace_back( std::move( newCand ) );851 }852 }853 854 /// Adds tuple member interpretations855 void addTupleMembers(856 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand,857 const Cost & addedCost, const ast::Expr * member858 ) {859 if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) {860 // get the value of the constant expression as an int, must be between 0 and the861 // length of the tuple to have meaning862 long long val = constantExpr->intValue();863 if ( val >= 0 && (unsigned long long)val < tupleType->size() ) {864 addCandidate(865 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val },866 addedCost );867 }868 }869 }870 871 void postvisit( const ast::UntypedExpr * untypedExpr ) {872 std::vector< CandidateFinder > argCandidates =873 selfFinder.findSubExprs( untypedExpr->args );874 875 // take care of possible tuple assignments876 // if not tuple assignment, handled as normal function call877 Tuples::handleTupleAssignment( selfFinder, untypedExpr, argCandidates );878 879 CandidateFinder funcFinder( context, tenv );880 if (auto nameExpr = untypedExpr->func.as<ast::NameExpr>()) {881 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);882 if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) {883 assertf(!argCandidates.empty(), "special function call without argument");884 for (auto & firstArgCand: argCandidates[0]) {885 ast::ptr<ast::Type> argType = firstArgCand->expr->result;886 firstArgCand->env.apply(argType);887 // strip references888 // xxx - is this correct?889 while (argType.as<ast::ReferenceType>()) argType = argType.as<ast::ReferenceType>()->base;890 891 // convert 1-tuple to plain type892 if (auto tuple = argType.as<ast::TupleType>()) {893 if (tuple->size() == 1) {894 argType = tuple->types[0];895 }896 }897 898 // if argType is an unbound type parameter, all special functions need to be searched.899 if (isUnboundType(argType)) {900 funcFinder.otypeKeys.clear();901 break;902 }903 904 if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer);905 // else if (const ast::EnumInstType * enumInst = argType.as<ast::EnumInstType>()) {906 // const ast::EnumDecl * enumDecl = enumInst->base; // Here907 // if ( const ast::Type* enumType = enumDecl->base ) {908 // // instance of enum (T) is a instance of type (T)909 // funcFinder.otypeKeys.insert(Mangle::mangle(enumType, Mangle::NoGenericParams | Mangle::Type));910 // } else {911 // // instance of an untyped enum is techically int912 // funcFinder.otypeKeys.insert(Mangle::mangle(enumDecl, Mangle::NoGenericParams | Mangle::Type));913 // }914 // }915 else funcFinder.otypeKeys.insert(Mangle::mangle(argType, Mangle::NoGenericParams | Mangle::Type));916 }917 }918 }919 // if candidates are already produced, do not fail920 // xxx - is it possible that handleTupleAssignment and main finder both produce candidates?921 // this means there exists ctor/assign functions with a tuple as first parameter.922 ResolvMode mode = {923 true, // adjust924 !untypedExpr->func.as<ast::NameExpr>(), // prune if not calling by name925 selfFinder.candidates.empty() // failfast if other options are not found926 };927 funcFinder.find( untypedExpr->func, mode );928 // short-circuit if no candidates929 // if ( funcFinder.candidates.empty() ) return;930 931 reason.code = NoMatch;932 933 // find function operators934 ast::ptr< ast::Expr > opExpr = new ast::NameExpr{ untypedExpr->location, "?()" }; // ??? why not ?{}935 CandidateFinder opFinder( context, tenv );936 // okay if there aren't any function operations937 opFinder.find( opExpr, ResolvMode::withoutFailFast() );938 PRINT(939 std::cerr << "known function ops:" << std::endl;940 print( std::cerr, opFinder.candidates, 1 );941 )942 943 // pre-explode arguments944 ExplodedArgs_new argExpansions;945 for ( const CandidateFinder & args : argCandidates ) {946 argExpansions.emplace_back();947 auto & argE = argExpansions.back();948 for ( const CandidateRef & arg : args ) { argE.emplace_back( *arg, symtab ); }949 }950 951 // Find function matches952 CandidateList found;953 SemanticErrorException errors;954 for ( CandidateRef & func : funcFinder ) {955 try {956 PRINT(957 std::cerr << "working on alternative:" << std::endl;958 print( std::cerr, *func, 2 );959 )960 961 // check if the type is a pointer to function962 const ast::Type * funcResult = func->expr->result->stripReferences();963 if ( auto pointer = dynamic_cast< const ast::PointerType * >( funcResult ) ) {964 if ( auto function = pointer->base.as< ast::FunctionType >() ) {965 CandidateRef newFunc{ new Candidate{ *func } };966 newFunc->expr =967 referenceToRvalueConversion( newFunc->expr, newFunc->cost );968 makeFunctionCandidates( newFunc, function, argExpansions, found );969 }970 } else if (971 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult )972 ) {973 if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) {974 if ( auto function = clz->bound.as< ast::FunctionType >() ) {975 CandidateRef newFunc{ new Candidate{ *func } };976 newFunc->expr =977 referenceToRvalueConversion( newFunc->expr, newFunc->cost );978 makeFunctionCandidates( newFunc, function, argExpansions, found );979 }980 }981 }982 } catch ( SemanticErrorException & e ) { errors.append( e ); }983 }984 985 // Find matches on function operators `?()`986 if ( ! opFinder.candidates.empty() ) {987 // add exploded function alternatives to front of argument list988 std::vector< ExplodedArg > funcE;989 funcE.reserve( funcFinder.candidates.size() );990 for ( const CandidateRef & func : funcFinder ) {991 funcE.emplace_back( *func, symtab );992 }993 argExpansions.emplace_front( std::move( funcE ) );994 995 for ( const CandidateRef & op : opFinder ) {996 try {997 // check if type is pointer-to-function998 const ast::Type * opResult = op->expr->result->stripReferences();999 if ( auto pointer = dynamic_cast< const ast::PointerType * >( opResult ) ) {1000 if ( auto function = pointer->base.as< ast::FunctionType >() ) {1001 CandidateRef newOp{ new Candidate{ *op} };1002 newOp->expr =1003 referenceToRvalueConversion( newOp->expr, newOp->cost );1004 makeFunctionCandidates( newOp, function, argExpansions, found );1005 }1006 }1007 } catch ( SemanticErrorException & e ) { errors.append( e ); }1008 }1009 }1010 1011 // Implement SFINAE; resolution errors are only errors if there aren't any non-error1012 // candidates1013 if ( found.empty() && ! errors.isEmpty() ) { throw errors; }1014 1015 // Compute conversion costs1016 for ( CandidateRef & withFunc : found ) {1017 Cost cvtCost = computeApplicationConversionCost( withFunc, symtab );1018 1019 PRINT(1020 auto appExpr = withFunc->expr.strict_as< ast::ApplicationExpr >();1021 auto pointer = appExpr->func->result.strict_as< ast::PointerType >();1022 auto function = pointer->base.strict_as< ast::FunctionType >();1023 1024 std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl;1025 std::cerr << "parameters are:" << std::endl;1026 ast::printAll( std::cerr, function->params, 2 );1027 std::cerr << "arguments are:" << std::endl;1028 ast::printAll( std::cerr, appExpr->args, 2 );1029 std::cerr << "bindings are:" << std::endl;1030 ast::print( std::cerr, withFunc->env, 2 );1031 std::cerr << "cost is: " << withFunc->cost << std::endl;1032 std::cerr << "cost of conversion is:" << cvtCost << std::endl;1033 )1034 1035 if ( cvtCost != Cost::infinity ) {1036 withFunc->cvtCost = cvtCost;1037 candidates.emplace_back( std::move( withFunc ) );1038 }1039 }1040 found = std::move( candidates );1041 1042 // use a new list so that candidates are not examined by addAnonConversions twice1043 CandidateList winners = findMinCost( found );1044 promoteCvtCost( winners );1045 1046 // function may return a struct/union value, in which case we need to add candidates1047 // for implicit conversions to each of the anonymous members, which must happen after1048 // `findMinCost`, since anon conversions are never the cheapest1049 for ( const CandidateRef & c : winners ) {1050 addAnonConversions( c );1051 }1052 spliceBegin( candidates, winners );1053 1054 if ( candidates.empty() && targetType && ! targetType->isVoid() ) {1055 // If resolution is unsuccessful with a target type, try again without, since it1056 // will sometimes succeed when it wouldn't with a target type binding.1057 // For example:1058 // forall( otype T ) T & ?[]( T *, ptrdiff_t );1059 // const char * x = "hello world";1060 // unsigned char ch = x[0];1061 // Fails with simple return type binding (xxx -- check this!) as follows:1062 // * T is bound to unsigned char1063 // * (x: const char *) is unified with unsigned char *, which fails1064 // xxx -- fix this better1065 targetType = nullptr;1066 postvisit( untypedExpr );1067 }1068 }1069 1070 /// true if expression is an lvalue1071 static bool isLvalue( const ast::Expr * x ) {1072 return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() );1073 }1074 1075 void postvisit( const ast::AddressExpr * addressExpr ) {1076 CandidateFinder finder( context, tenv );1077 finder.find( addressExpr->arg );1078 1079 if( finder.candidates.empty() ) return;1080 1081 reason.code = NoMatch;1082 1083 for ( CandidateRef & r : finder.candidates ) {1084 if ( ! isLvalue( r->expr ) ) continue;1085 addCandidate( *r, new ast::AddressExpr{ addressExpr->location, r->expr } );1086 }1087 }1088 1089 void postvisit( const ast::LabelAddressExpr * labelExpr ) {1090 addCandidate( labelExpr, tenv );1091 }1092 1093 void postvisit( const ast::CastExpr * castExpr ) {1094 ast::ptr< ast::Type > toType = castExpr->result;1095 assert( toType );1096 toType = resolveTypeof( toType, context );1097 toType = adjustExprType( toType, tenv, symtab );1098 1099 CandidateFinder finder( context, tenv, toType );1100 finder.find( castExpr->arg, ResolvMode::withAdjustment() );1101 1102 if( !finder.candidates.empty() ) reason.code = NoMatch;1103 1104 CandidateList matches;1105 for ( CandidateRef & cand : finder.candidates ) {1106 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;1107 ast::OpenVarSet open( cand->open );1108 1109 cand->env.extractOpenVars( open );1110 1111 // It is possible that a cast can throw away some values in a multiply-valued1112 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the1113 // subexpression results that are cast directly. The candidate is invalid if it1114 // has fewer results than there are types to cast to.1115 int discardedValues = cand->expr->result->size() - toType->size();1116 if ( discardedValues < 0 ) continue;1117 1118 // unification run for side-effects1119 unify( toType, cand->expr->result, cand->env, need, have, open, symtab );1120 Cost thisCost =1121 (castExpr->isGenerated == ast::GeneratedFlag::GeneratedCast)1122 ? conversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env )1123 : castCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env );1124 1125 PRINT(1126 std::cerr << "working on cast with result: " << toType << std::endl;1127 std::cerr << "and expr type: " << cand->expr->result << std::endl;1128 std::cerr << "env: " << cand->env << std::endl;1129 )1130 if ( thisCost != Cost::infinity ) {1131 PRINT(1132 std::cerr << "has finite cost." << std::endl;1133 )1134 // count one safe conversion for each value that is thrown away1135 thisCost.incSafe( discardedValues );1136 CandidateRef newCand = std::make_shared<Candidate>(1137 restructureCast( cand->expr, toType, castExpr->isGenerated ),1138 copy( cand->env ), std::move( open ), std::move( need ), cand->cost,1139 cand->cost + thisCost );1140 inferParameters( newCand, matches );1141 }1142 }1143 1144 // select first on argument cost, then conversion cost1145 CandidateList minArgCost = findMinCost( matches );1146 promoteCvtCost( minArgCost );1147 candidates = findMinCost( minArgCost );1148 }1149 1150 void postvisit( const ast::VirtualCastExpr * castExpr ) {1151 assertf( castExpr->result, "Implicit virtual cast targets not yet supported." );1152 CandidateFinder finder( context, tenv );1153 // don't prune here, all alternatives guaranteed to have same type1154 finder.find( castExpr->arg, ResolvMode::withoutPrune() );1155 for ( CandidateRef & r : finder.candidates ) {1156 addCandidate(1157 *r,1158 new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } );1159 }1160 }1161 1162 void postvisit( const ast::KeywordCastExpr * castExpr ) {1163 const auto & loc = castExpr->location;1164 assertf( castExpr->result, "Cast target should have been set in Validate." );1165 auto ref = castExpr->result.strict_as<ast::ReferenceType>();1166 auto inst = ref->base.strict_as<ast::StructInstType>();1167 auto target = inst->base.get();1168 1169 CandidateFinder finder( context, tenv );1170 1171 auto pick_alternatives = [target, this](CandidateList & found, bool expect_ref) {1172 for(auto & cand : found) {1173 const ast::Type * expr = cand->expr->result.get();1174 if(expect_ref) {1175 auto res = dynamic_cast<const ast::ReferenceType*>(expr);1176 if(!res) { continue; }1177 expr = res->base.get();1178 }1179 1180 if(auto insttype = dynamic_cast<const ast::TypeInstType*>(expr)) {1181 auto td = cand->env.lookup(*insttype);1182 if(!td) { continue; }1183 expr = td->bound.get();1184 }1185 1186 if(auto base = dynamic_cast<const ast::StructInstType*>(expr)) {1187 if(base->base == target) {1188 candidates.push_back( std::move(cand) );1189 reason.code = NoReason;1190 }1191 }1192 }1193 };1194 1195 try {1196 // Attempt 1 : turn (thread&)X into (thread$&)X.__thrd1197 // Clone is purely for memory management1198 std::unique_ptr<const ast::Expr> tech1 { new ast::UntypedMemberExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.field), castExpr->arg) };1199 1200 // don't prune here, since it's guaranteed all alternatives will have the same type1201 finder.find( tech1.get(), ResolvMode::withoutPrune() );1202 pick_alternatives(finder.candidates, false);1203 1204 return;1205 } catch(SemanticErrorException & ) {}1206 1207 // Fallback : turn (thread&)X into (thread$&)get_thread(X)1208 std::unique_ptr<const ast::Expr> fallback { ast::UntypedExpr::createDeref(loc, new ast::UntypedExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.getter), { castExpr->arg })) };1209 // don't prune here, since it's guaranteed all alternatives will have the same type1210 finder.find( fallback.get(), ResolvMode::withoutPrune() );1211 1212 pick_alternatives(finder.candidates, true);1213 1214 // Whatever happens here, we have no more fallbacks1215 }1216 1217 void postvisit( const ast::UntypedMemberExpr * memberExpr ) {1218 CandidateFinder aggFinder( context, tenv );1219 aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() );1220 for ( CandidateRef & agg : aggFinder.candidates ) {1221 // it's okay for the aggregate expression to have reference type -- cast it to the1222 // base type to treat the aggregate as the referenced value1223 Cost addedCost = Cost::zero;1224 agg->expr = referenceToRvalueConversion( agg->expr, addedCost );1225 1226 // find member of the given type1227 if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) {1228 addAggMembers(1229 structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );1230 } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) {1231 addAggMembers(1232 unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );1233 } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) {1234 addTupleMembers( tupleType, agg->expr, *agg, addedCost, memberExpr->member );1235 }1236 }1237 }1238 1239 void postvisit( const ast::MemberExpr * memberExpr ) {1240 addCandidate( memberExpr, tenv );1241 }1242 1243 void postvisit( const ast::NameExpr * nameExpr ) {1244 std::vector< ast::SymbolTable::IdData > declList;1245 if (!selfFinder.otypeKeys.empty()) {1246 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);1247 assertf(kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS, "special lookup with non-special target: %s", nameExpr->name.c_str());1248 1249 for (auto & otypeKey: selfFinder.otypeKeys) {1250 auto result = symtab.specialLookupId(kind, otypeKey);1251 declList.insert(declList.end(), std::make_move_iterator(result.begin()), std::make_move_iterator(result.end()));1252 }1253 }1254 else {1255 declList = symtab.lookupId( nameExpr->name );1256 }1257 PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )1258 1259 if( declList.empty() ) return;1260 1261 reason.code = NoMatch;1262 1263 for ( auto & data : declList ) {1264 Cost cost = Cost::zero;1265 ast::Expr * newExpr = data.combine( nameExpr->location, cost );1266 1267 CandidateRef newCand = std::make_shared<Candidate>(1268 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero,1269 cost );1270 1271 if (newCand->expr->env) {1272 newCand->env.add(*newCand->expr->env);1273 auto mutExpr = newCand->expr.get_and_mutate();1274 mutExpr->env = nullptr;1275 newCand->expr = mutExpr;1276 }1277 1278 PRINT(1279 std::cerr << "decl is ";1280 ast::print( std::cerr, data.id );1281 std::cerr << std::endl;1282 std::cerr << "newExpr is ";1283 ast::print( std::cerr, newExpr );1284 std::cerr << std::endl;1285 )1286 newCand->expr = ast::mutate_field(1287 newCand->expr.get(), &ast::Expr::result,1288 renameTyVars( newCand->expr->result ) );1289 // add anonymous member interpretations whenever an aggregate value type is seen1290 // as a name expression1291 addAnonConversions( newCand );1292 candidates.emplace_back( std::move( newCand ) );1293 }1294 }1295 1296 void postvisit( const ast::VariableExpr * variableExpr ) {1297 // not sufficient to just pass `variableExpr` here, type might have changed since1298 // creation1299 addCandidate(1300 new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv );1301 }1302 1303 void postvisit( const ast::ConstantExpr * constantExpr ) {1304 addCandidate( constantExpr, tenv );1305 }1306 1307 void postvisit( const ast::SizeofExpr * sizeofExpr ) {1308 if ( sizeofExpr->type ) {1309 addCandidate(1310 new ast::SizeofExpr{1311 sizeofExpr->location, resolveTypeof( sizeofExpr->type, context ) },1312 tenv );1313 } else {1314 // find all candidates for the argument to sizeof1315 CandidateFinder finder( context, tenv );1316 finder.find( sizeofExpr->expr );1317 // find the lowest-cost candidate, otherwise ambiguous1318 CandidateList winners = findMinCost( finder.candidates );1319 if ( winners.size() != 1 ) {1320 SemanticError(1321 sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " );1322 }1323 // return the lowest-cost candidate1324 CandidateRef & choice = winners.front();1325 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );1326 choice->cost = Cost::zero;1327 addCandidate( *choice, new ast::SizeofExpr{ sizeofExpr->location, choice->expr } );1328 }1329 }1330 1331 void postvisit( const ast::AlignofExpr * alignofExpr ) {1332 if ( alignofExpr->type ) {1333 addCandidate(1334 new ast::AlignofExpr{1335 alignofExpr->location, resolveTypeof( alignofExpr->type, context ) },1336 tenv );1337 } else {1338 // find all candidates for the argument to alignof1339 CandidateFinder finder( context, tenv );1340 finder.find( alignofExpr->expr );1341 // find the lowest-cost candidate, otherwise ambiguous1342 CandidateList winners = findMinCost( finder.candidates );1343 if ( winners.size() != 1 ) {1344 SemanticError(1345 alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " );1346 }1347 // return the lowest-cost candidate1348 CandidateRef & choice = winners.front();1349 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );1350 choice->cost = Cost::zero;1351 addCandidate(1352 *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } );1353 }1354 }1355 1356 void postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ) {1357 const ast::BaseInstType * aggInst;1358 if (( aggInst = offsetofExpr->type.as< ast::StructInstType >() )) ;1359 else if (( aggInst = offsetofExpr->type.as< ast::UnionInstType >() )) ;1360 else return;1361 1362 for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) {1363 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member );1364 addCandidate(1365 new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv );1366 }1367 }1368 1369 void postvisit( const ast::OffsetofExpr * offsetofExpr ) {1370 addCandidate( offsetofExpr, tenv );1371 }1372 1373 void postvisit( const ast::OffsetPackExpr * offsetPackExpr ) {1374 addCandidate( offsetPackExpr, tenv );1375 }1376 1377 void postvisit( const ast::LogicalExpr * logicalExpr ) {1378 CandidateFinder finder1( context, tenv );1379 finder1.find( logicalExpr->arg1, ResolvMode::withAdjustment() );1380 if ( finder1.candidates.empty() ) return;1381 1382 CandidateFinder finder2( context, tenv );1383 finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() );1384 if ( finder2.candidates.empty() ) return;1385 1386 reason.code = NoMatch;1387 1388 for ( const CandidateRef & r1 : finder1.candidates ) {1389 for ( const CandidateRef & r2 : finder2.candidates ) {1390 ast::TypeEnvironment env{ r1->env };1391 env.simpleCombine( r2->env );1392 ast::OpenVarSet open{ r1->open };1393 mergeOpenVars( open, r2->open );1394 ast::AssertionSet need;1395 mergeAssertionSet( need, r1->need );1396 mergeAssertionSet( need, r2->need );1397 1398 addCandidate(1399 new ast::LogicalExpr{1400 logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd },1401 std::move( env ), std::move( open ), std::move( need ), r1->cost + r2->cost );1402 }1403 }1404 }1405 1406 void postvisit( const ast::ConditionalExpr * conditionalExpr ) {1407 // candidates for condition1408 CandidateFinder finder1( context, tenv );1409 finder1.find( conditionalExpr->arg1, ResolvMode::withAdjustment() );1410 if ( finder1.candidates.empty() ) return;1411 1412 // candidates for true result1413 CandidateFinder finder2( context, tenv );1414 finder2.find( conditionalExpr->arg2, ResolvMode::withAdjustment() );1415 if ( finder2.candidates.empty() ) return;1416 1417 // candidates for false result1418 CandidateFinder finder3( context, tenv );1419 finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() );1420 if ( finder3.candidates.empty() ) return;1421 1422 reason.code = NoMatch;1423 1424 for ( const CandidateRef & r1 : finder1.candidates ) {1425 for ( const CandidateRef & r2 : finder2.candidates ) {1426 for ( const CandidateRef & r3 : finder3.candidates ) {1427 ast::TypeEnvironment env{ r1->env };1428 env.simpleCombine( r2->env );1429 env.simpleCombine( r3->env );1430 ast::OpenVarSet open{ r1->open };1431 mergeOpenVars( open, r2->open );1432 mergeOpenVars( open, r3->open );1433 ast::AssertionSet need;1434 mergeAssertionSet( need, r1->need );1435 mergeAssertionSet( need, r2->need );1436 mergeAssertionSet( need, r3->need );1437 ast::AssertionSet have;1438 1439 // unify true and false results, then infer parameters to produce new1440 // candidates1441 ast::ptr< ast::Type > common;1442 if (1443 unify(1444 r2->expr->result, r3->expr->result, env, need, have, open, symtab,1445 common )1446 ) {1447 // generate typed expression1448 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{1449 conditionalExpr->location, r1->expr, r2->expr, r3->expr };1450 newExpr->result = common ? common : r2->expr->result;1451 // convert both options to result type1452 Cost cost = r1->cost + r2->cost + r3->cost;1453 newExpr->arg2 = computeExpressionConversionCost(1454 newExpr->arg2, newExpr->result, symtab, env, cost );1455 newExpr->arg3 = computeExpressionConversionCost(1456 newExpr->arg3, newExpr->result, symtab, env, cost );1457 // output candidate1458 CandidateRef newCand = std::make_shared<Candidate>(1459 newExpr, std::move( env ), std::move( open ), std::move( need ), cost );1460 inferParameters( newCand, candidates );1461 }1462 }1463 }1464 }1465 }1466 1467 void postvisit( const ast::CommaExpr * commaExpr ) {1468 ast::TypeEnvironment env{ tenv };1469 ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, context, env );1470 1471 CandidateFinder finder2( context, env );1472 finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() );1473 1474 for ( const CandidateRef & r2 : finder2.candidates ) {1475 addCandidate( *r2, new ast::CommaExpr{ commaExpr->location, arg1, r2->expr } );1476 }1477 }1478 1479 void postvisit( const ast::ImplicitCopyCtorExpr * ctorExpr ) {1480 addCandidate( ctorExpr, tenv );1481 }1482 1483 void postvisit( const ast::ConstructorExpr * ctorExpr ) {1484 CandidateFinder finder( context, tenv );1485 finder.find( ctorExpr->callExpr, ResolvMode::withoutPrune() );1486 for ( CandidateRef & r : finder.candidates ) {1487 addCandidate( *r, new ast::ConstructorExpr{ ctorExpr->location, r->expr } );1488 }1489 }1490 1491 void postvisit( const ast::RangeExpr * rangeExpr ) {1492 // resolve low and high, accept candidates where low and high types unify1493 CandidateFinder finder1( context, tenv );1494 finder1.find( rangeExpr->low, ResolvMode::withAdjustment() );1495 if ( finder1.candidates.empty() ) return;1496 1497 CandidateFinder finder2( context, tenv );1498 finder2.find( rangeExpr->high, ResolvMode::withAdjustment() );1499 if ( finder2.candidates.empty() ) return;1500 1501 reason.code = NoMatch;1502 1503 for ( const CandidateRef & r1 : finder1.candidates ) {1504 for ( const CandidateRef & r2 : finder2.candidates ) {1505 ast::TypeEnvironment env{ r1->env };1506 env.simpleCombine( r2->env );1507 ast::OpenVarSet open{ r1->open };1508 mergeOpenVars( open, r2->open );1509 ast::AssertionSet need;1510 mergeAssertionSet( need, r1->need );1511 mergeAssertionSet( need, r2->need );1512 ast::AssertionSet have;1513 1514 ast::ptr< ast::Type > common;1515 if (1516 unify(1517 r1->expr->result, r2->expr->result, env, need, have, open, symtab,1518 common )1519 ) {1520 // generate new expression1521 ast::RangeExpr * newExpr =1522 new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr };1523 newExpr->result = common ? common : r1->expr->result;1524 // add candidate1525 CandidateRef newCand = std::make_shared<Candidate>(1526 newExpr, std::move( env ), std::move( open ), std::move( need ),1527 r1->cost + r2->cost );1528 inferParameters( newCand, candidates );1529 }1530 }1531 }1532 }1533 1534 void postvisit( const ast::UntypedTupleExpr * tupleExpr ) {1535 std::vector< CandidateFinder > subCandidates =1536 selfFinder.findSubExprs( tupleExpr->exprs );1537 std::vector< CandidateList > possibilities;1538 combos( subCandidates.begin(), subCandidates.end(), back_inserter( possibilities ) );1539 1540 for ( const CandidateList & subs : possibilities ) {1541 std::vector< ast::ptr< ast::Expr > > exprs;1542 exprs.reserve( subs.size() );1543 for ( const CandidateRef & sub : subs ) { exprs.emplace_back( sub->expr ); }1544 1545 ast::TypeEnvironment env;1546 ast::OpenVarSet open;1547 ast::AssertionSet need;1548 for ( const CandidateRef & sub : subs ) {1549 env.simpleCombine( sub->env );1550 mergeOpenVars( open, sub->open );1551 mergeAssertionSet( need, sub->need );1552 }1553 1554 addCandidate(1555 new ast::TupleExpr{ tupleExpr->location, std::move( exprs ) },1556 std::move( env ), std::move( open ), std::move( need ), sumCost( subs ) );1557 }1558 }1559 1560 void postvisit( const ast::TupleExpr * tupleExpr ) {1561 addCandidate( tupleExpr, tenv );1562 }1563 1564 void postvisit( const ast::TupleIndexExpr * tupleExpr ) {1565 addCandidate( tupleExpr, tenv );1566 }1567 1568 void postvisit( const ast::TupleAssignExpr * tupleExpr ) {1569 addCandidate( tupleExpr, tenv );1570 }1571 1572 void postvisit( const ast::UniqueExpr * unqExpr ) {1573 CandidateFinder finder( context, tenv );1574 finder.find( unqExpr->expr, ResolvMode::withAdjustment() );1575 for ( CandidateRef & r : finder.candidates ) {1576 // ensure that the the id is passed on so that the expressions are "linked"1577 addCandidate( *r, new ast::UniqueExpr{ unqExpr->location, r->expr, unqExpr->id } );1578 }1579 }1580 1581 void postvisit( const ast::StmtExpr * stmtExpr ) {1582 addCandidate( resolveStmtExpr( stmtExpr, context ), tenv );1583 }1584 1585 void postvisit( const ast::UntypedInitExpr * initExpr ) {1586 // handle each option like a cast1587 CandidateList matches;1588 PRINT(1589 std::cerr << "untyped init expr: " << initExpr << std::endl;1590 )1591 // O(n^2) checks of d-types with e-types1592 for ( const ast::InitAlternative & initAlt : initExpr->initAlts ) {1593 // calculate target type1594 const ast::Type * toType = resolveTypeof( initAlt.type, context );1595 toType = adjustExprType( toType, tenv, symtab );1596 // The call to find must occur inside this loop, otherwise polymorphic return1597 // types are not bound to the initialization type, since return type variables are1598 // only open for the duration of resolving the UntypedExpr.1599 CandidateFinder finder( context, tenv, toType );1600 finder.find( initExpr->expr, ResolvMode::withAdjustment() );1601 for ( CandidateRef & cand : finder.candidates ) {1602 if(reason.code == NotFound) reason.code = NoMatch;1603 1604 ast::TypeEnvironment env{ cand->env };1605 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;1606 ast::OpenVarSet open{ cand->open };1607 1608 PRINT(1609 std::cerr << " @ " << toType << " " << initAlt.designation << std::endl;1610 )1611 1612 // It is possible that a cast can throw away some values in a multiply-valued1613 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of1614 // the subexpression results that are cast directly. The candidate is invalid1615 // if it has fewer results than there are types to cast to.1616 int discardedValues = cand->expr->result->size() - toType->size();1617 if ( discardedValues < 0 ) continue;1618 1619 // unification run for side-effects1620 bool canUnify = unify( toType, cand->expr->result, env, need, have, open, symtab );1621 (void) canUnify;1622 Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(),1623 symtab, env );1624 PRINT(1625 Cost legacyCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(),1626 symtab, env );1627 std::cerr << "Considering initialization:";1628 std::cerr << std::endl << " FROM: " << cand->expr->result << std::endl;1629 std::cerr << std::endl << " TO: " << toType << std::endl;1630 std::cerr << std::endl << " Unification " << (canUnify ? "succeeded" : "failed");1631 std::cerr << std::endl << " Legacy cost " << legacyCost;1632 std::cerr << std::endl << " New cost " << thisCost;1633 std::cerr << std::endl;1634 )1635 if ( thisCost != Cost::infinity ) {1636 // count one safe conversion for each value that is thrown away1637 thisCost.incSafe( discardedValues );1638 CandidateRef newCand = std::make_shared<Candidate>(1639 new ast::InitExpr{1640 initExpr->location, restructureCast( cand->expr, toType ),1641 initAlt.designation },1642 std::move(env), std::move( open ), std::move( need ), cand->cost, thisCost );1643 inferParameters( newCand, matches );1644 }1645 }1646 1647 }1648 1649 // select first on argument cost, then conversion cost1650 CandidateList minArgCost = findMinCost( matches );1651 promoteCvtCost( minArgCost );1652 candidates = findMinCost( minArgCost );1653 }1654 1655 void postvisit( const ast::InitExpr * ) {1656 assertf( false, "CandidateFinder should never see a resolved InitExpr." );1657 }1658 1659 void postvisit( const ast::DeletedExpr * ) {1660 assertf( false, "CandidateFinder should never see a DeletedExpr." );1661 }1662 1663 void postvisit( const ast::GenericExpr * ) {1664 assertf( false, "_Generic is not yet supported." );1665 }1666 };1667 1668 // size_t Finder::traceId = Stats::Heap::new_stacktrace_id("Finder");1669 /// Prunes a list of candidates down to those that have the minimum conversion cost for a given1670 /// return type. Skips ambiguous candidates.1671 1672 } // anonymous namespace1673 1674 bool CandidateFinder::pruneCandidates( CandidateList & candidates, CandidateList & out, std::vector<std::string> & errors ) {1675 struct PruneStruct {1676 CandidateRef candidate;1677 bool ambiguous;1678 1679 PruneStruct() = default;1680 PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {}1681 };1682 1683 // find lowest-cost candidate for each type1684 std::unordered_map< std::string, PruneStruct > selected;1685 // attempt to skip satisfyAssertions on more expensive alternatives if better options have been found1686 std::sort(candidates.begin(), candidates.end(), [](const CandidateRef & x, const CandidateRef & y){return x->cost < y->cost;});1687 for ( CandidateRef & candidate : candidates ) {1688 std::string mangleName;1689 {1690 ast::ptr< ast::Type > newType = candidate->expr->result;1691 assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get());1692 candidate->env.apply( newType );1693 mangleName = Mangle::mangle( newType );1694 }1695 1696 auto found = selected.find( mangleName );1697 if (found != selected.end() && found->second.candidate->cost < candidate->cost) {1698 PRINT(1699 std::cerr << "cost " << candidate->cost << " loses to "1700 << found->second.candidate->cost << std::endl;1701 )1702 continue;1703 }1704 1705 // xxx - when do satisfyAssertions produce more than 1 result?1706 // this should only happen when initial result type contains1707 // unbound type parameters, then it should never be pruned by1708 // the previous step, since renameTyVars guarantees the mangled name1709 // is unique.1710 CandidateList satisfied;1711 bool needRecomputeKey = false;1712 if (candidate->need.empty()) {1713 satisfied.emplace_back(candidate);1714 }1715 else {1716 satisfyAssertions(candidate, context.symtab, satisfied, errors);1717 needRecomputeKey = true;1718 }1719 1720 for (auto & newCand : satisfied) {1721 // recomputes type key, if satisfyAssertions changed it1722 if (needRecomputeKey)1723 {1724 ast::ptr< ast::Type > newType = newCand->expr->result;1725 assertf(newCand->expr->result, "Result of expression %p for candidate is null", newCand->expr.get());1726 newCand->env.apply( newType );1727 mangleName = Mangle::mangle( newType );1728 }1729 auto found = selected.find( mangleName );1730 if ( found != selected.end() ) {1731 if ( newCand->cost < found->second.candidate->cost ) {1732 PRINT(1733 std::cerr << "cost " << newCand->cost << " beats "1734 << found->second.candidate->cost << std::endl;1735 )1736 1737 found->second = PruneStruct{ newCand };1738 } else if ( newCand->cost == found->second.candidate->cost ) {1739 // if one of the candidates contains a deleted identifier, can pick the other,1740 // since deleted expressions should not be ambiguous if there is another option1741 // that is at least as good1742 if ( findDeletedExpr( newCand->expr ) ) {1743 // do nothing1744 PRINT( std::cerr << "candidate is deleted" << std::endl; )1745 } else if ( findDeletedExpr( found->second.candidate->expr ) ) {1746 PRINT( std::cerr << "current is deleted" << std::endl; )1747 found->second = PruneStruct{ newCand };1748 } else {1749 PRINT( std::cerr << "marking ambiguous" << std::endl; )1750 found->second.ambiguous = true;1751 }1752 } else {1753 // xxx - can satisfyAssertions increase the cost?1754 PRINT(1755 std::cerr << "cost " << newCand->cost << " loses to "1756 << found->second.candidate->cost << std::endl;1757 )1758 }1759 } else {1760 selected.emplace_hint( found, mangleName, newCand );1761 }1762 }1763 }1764 1765 // report unambiguous min-cost candidates1766 // CandidateList out;1767 for ( auto & target : selected ) {1768 if ( target.second.ambiguous ) continue;1769 1770 CandidateRef cand = target.second.candidate;1771 1772 ast::ptr< ast::Type > newResult = cand->expr->result;1773 cand->env.applyFree( newResult );1774 cand->expr = ast::mutate_field(1775 cand->expr.get(), &ast::Expr::result, std::move( newResult ) );1776 1777 out.emplace_back( cand );1778 }1779 // if everything is lost in satisfyAssertions, report the error1780 return !selected.empty();1781 }1782 1783 void CandidateFinder::find( const ast::Expr * expr, ResolvMode mode ) {1784 // Find alternatives for expression1785 ast::Pass<Finder> finder{ *this };1786 expr->accept( finder );1787 1788 if ( mode.failFast && candidates.empty() ) {1789 switch(finder.core.reason.code) {1790 case Finder::NotFound:1791 { SemanticError( expr, "No alternatives for expression " ); break; }1792 case Finder::NoMatch:1793 { SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; }1794 case Finder::ArgsToFew:1795 case Finder::ArgsToMany:1796 case Finder::RetsToFew:1797 case Finder::RetsToMany:1798 case Finder::NoReason:1799 default:1800 { SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); }1801 }1802 }1803 1804 /*1805 if ( mode.satisfyAssns || mode.prune ) {1806 // trim candidates to just those where the assertions are satisfiable1807 // - necessary pre-requisite to pruning1808 CandidateList satisfied;1809 std::vector< std::string > errors;1810 for ( CandidateRef & candidate : candidates ) {1811 satisfyAssertions( candidate, localSyms, satisfied, errors );1812 }1813 1814 // fail early if none such1815 if ( mode.failFast && satisfied.empty() ) {1816 std::ostringstream stream;1817 stream << "No alternatives with satisfiable assertions for " << expr << "\n";1818 for ( const auto& err : errors ) {1819 stream << err;1820 }1821 SemanticError( expr->location, stream.str() );1822 }1823 1824 // reset candidates1825 candidates = move( satisfied );1826 }1827 */1828 1829 if ( mode.prune ) {1830 // trim candidates to single best one1831 PRINT(1832 std::cerr << "alternatives before prune:" << std::endl;1833 print( std::cerr, candidates );1834 )1835 1836 CandidateList pruned;1837 std::vector<std::string> errors;1838 bool found = pruneCandidates( candidates, pruned, errors );1839 1840 if ( mode.failFast && pruned.empty() ) {1841 std::ostringstream stream;1842 if (found) {1843 CandidateList winners = findMinCost( candidates );1844 stream << "Cannot choose between " << winners.size() << " alternatives for "1845 "expression\n";1846 ast::print( stream, expr );1847 stream << " Alternatives are:\n";1848 print( stream, winners, 1 );1849 SemanticError( expr->location, stream.str() );1850 }1851 else {1852 stream << "No alternatives with satisfiable assertions for " << expr << "\n";1853 for ( const auto& err : errors ) {1854 stream << err;1855 }1856 SemanticError( expr->location, stream.str() );1857 }1858 }1859 1860 auto oldsize = candidates.size();1861 candidates = std::move( pruned );1862 1863 PRINT(1864 std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl;1865 )1866 PRINT(1867 std::cerr << "there are " << candidates.size() << " alternatives after elimination"1868 << std::endl;1869 )1870 }1871 1872 // adjust types after pruning so that types substituted by pruneAlternatives are correctly1873 // adjusted1874 if ( mode.adjust ) {1875 for ( CandidateRef & r : candidates ) {1876 r->expr = ast::mutate_field(1877 r->expr.get(), &ast::Expr::result,1878 adjustExprType( r->expr->result, r->env, context.symtab ) );1879 }1880 }1881 1882 // Central location to handle gcc extension keyword, etc. for all expressions1883 for ( CandidateRef & r : candidates ) {1884 if ( r->expr->extension != expr->extension ) {1885 r->expr.get_and_mutate()->extension = expr->extension;1886 }1887 }1888 }1889 1890 std::vector< CandidateFinder > CandidateFinder::findSubExprs(1891 const std::vector< ast::ptr< ast::Expr > > & xs1892 ) {1893 std::vector< CandidateFinder > out;1894 1895 for ( const auto & x : xs ) {1896 out.emplace_back( context, env );1897 out.back().find( x, ResolvMode::withAdjustment() );1898 1899 PRINT(1900 std::cerr << "findSubExprs" << std::endl;1901 print( std::cerr, out.back().candidates );1902 )1903 }1904 1905 return out;1906 }1907 1908 1970 } // namespace ResolvExpr 1909 1971 -
src/ResolvExpr/CurrentObject.cc
ra50fdfb r6e1e2d0 9 9 // Author : Rob Schluntz 10 10 // Created On : Tue Jun 13 15:28:32 2017 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Jul 1 09:16:01 202213 // Update Count : 1 511 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Apr 10 9:40:00 2023 13 // Update Count : 18 14 14 // 15 15 … … 593 593 594 594 namespace ast { 595 /// Iterates members of a type by initializer. 596 class MemberIterator { 597 public: 598 virtual ~MemberIterator() {} 599 600 /// Internal set position based on iterator ranges. 601 virtual void setPosition( 602 std::deque< ptr< Expr > >::const_iterator it, 603 std::deque< ptr< Expr > >::const_iterator end ) = 0; 604 605 /// Walks the current object using the given designators as a guide. 606 void setPosition( const std::deque< ptr< Expr > > & designators ) { 607 setPosition( designators.begin(), designators.end() ); 608 } 609 610 /// Retrieve the list of possible (Type,Designation) pairs for the 611 /// current position in the current object. 612 virtual std::deque< InitAlternative > operator* () const = 0; 613 614 /// True if the iterator is not currently at the end. 615 virtual operator bool() const = 0; 616 617 /// Moves the iterator by one member in the current object. 618 virtual MemberIterator & bigStep() = 0; 619 620 /// Moves the iterator by one member in the current subobject. 621 virtual MemberIterator & smallStep() = 0; 622 623 /// The type of the current object. 624 virtual const Type * getType() = 0; 625 626 /// The type of the current subobject. 627 virtual const Type * getNext() = 0; 628 629 /// Helper for operator*; aggregates must add designator to each init 630 /// alternative, but adding designators in operator* creates duplicates. 631 virtual std::deque< InitAlternative > first() const = 0; 632 }; 633 595 634 /// create a new MemberIterator that traverses a type correctly 596 635 MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type ); … … 632 671 }; 633 672 634 /// Iterates array types 635 class ArrayIterator final : public MemberIterator { 673 /// Iterates over an indexed type: 674 class IndexIterator : public MemberIterator { 675 protected: 636 676 CodeLocation location; 637 const ArrayType * array = nullptr;638 const Type * base = nullptr;639 677 size_t index = 0; 640 678 size_t size = 0; 641 std::unique_ptr< MemberIterator > memberIter; 642 643 void setSize( const Expr * expr ) { 644 auto res = eval( expr ); 645 if ( ! res.second ) { 646 SemanticError( location, toString( "Array designator must be a constant expression: ", expr ) ); 647 } 648 size = res.first; 649 } 650 651 public: 652 ArrayIterator( const CodeLocation & loc, const ArrayType * at ) : location( loc ), array( at ), base( at->base ) { 653 PRINT( std::cerr << "Creating array iterator: " << at << std::endl; ) 654 memberIter.reset( createMemberIterator( loc, base ) ); 655 if ( at->isVarLen ) { 656 SemanticError( location, at, "VLA initialization does not support @=: " ); 657 } 658 setSize( at->dimension ); 659 } 679 std::unique_ptr<MemberIterator> memberIter; 680 public: 681 IndexIterator( const CodeLocation & loc, size_t size ) : 682 location( loc ), size( size ) 683 {} 660 684 661 685 void setPosition( const Expr * expr ) { … … 666 690 auto arg = eval( expr ); 667 691 index = arg.first; 668 return;669 692 670 693 // if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) { … … 684 707 685 708 void setPosition( 686 std::deque< ptr< Expr >>::const_iterator begin,687 std::deque< ptr< Expr >>::const_iterator end709 std::deque<ast::ptr<ast::Expr>>::const_iterator begin, 710 std::deque<ast::ptr<ast::Expr>>::const_iterator end 688 711 ) override { 689 712 if ( begin == end ) return; … … 696 719 697 720 operator bool() const override { return index < size; } 721 }; 722 723 /// Iterates over the members of array types: 724 class ArrayIterator final : public IndexIterator { 725 const ArrayType * array = nullptr; 726 const Type * base = nullptr; 727 728 size_t getSize( const Expr * expr ) { 729 auto res = eval( expr ); 730 if ( !res.second ) { 731 SemanticError( location, toString( "Array designator must be a constant expression: ", expr ) ); 732 } 733 return res.first; 734 } 735 736 public: 737 ArrayIterator( const CodeLocation & loc, const ArrayType * at ) : 738 IndexIterator( loc, getSize( at->dimension) ), 739 array( at ), base( at->base ) { 740 PRINT( std::cerr << "Creating array iterator: " << at << std::endl; ) 741 memberIter.reset( createMemberIterator( loc, base ) ); 742 if ( at->isVarLen ) { 743 SemanticError( location, at, "VLA initialization does not support @=: " ); 744 } 745 } 698 746 699 747 ArrayIterator & bigStep() override { … … 834 882 835 883 const Type * getNext() final { 836 return ( memberIter && *memberIter ) ? memberIter->getType() : nullptr; 884 bool hasMember = memberIter && *memberIter; 885 return hasMember ? memberIter->getType() : nullptr; 837 886 } 838 887 … … 898 947 }; 899 948 900 class TupleIterator final : public AggregateIterator { 901 public: 902 TupleIterator( const CodeLocation & loc, const TupleType * inst ) 903 : AggregateIterator( 904 loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members 905 ) {} 906 907 operator bool() const override { 908 return curMember != members.end() || (memberIter && *memberIter); 949 /// Iterates across the positions in a tuple: 950 class TupleIterator final : public IndexIterator { 951 ast::TupleType const * const tuple; 952 953 const ast::Type * typeAtIndex() const { 954 assert( index < size ); 955 return tuple->types[ index ].get(); 956 } 957 958 public: 959 TupleIterator( const CodeLocation & loc, const TupleType * type ) 960 : IndexIterator( loc, type->size() ), tuple( type ) { 961 PRINT( std::cerr << "Creating tuple iterator: " << type << std::endl; ) 962 memberIter.reset( createMemberIterator( loc, typeAtIndex() ) ); 909 963 } 910 964 911 965 TupleIterator & bigStep() override { 912 PRINT( std::cerr << "bigStep in " << kind << std::endl; ) 913 atbegin = false; 914 memberIter = nullptr; 915 curType = nullptr; 916 while ( curMember != members.end() ) { 917 ++curMember; 918 if ( init() ) return *this; 919 } 966 ++index; 967 memberIter.reset( index < size ? 968 createMemberIterator( location, typeAtIndex() ) : nullptr ); 920 969 return *this; 970 } 971 972 TupleIterator & smallStep() override { 973 if ( memberIter ) { 974 PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; ) 975 memberIter->smallStep(); 976 if ( !memberIter ) { 977 PRINT( std::cerr << "has valid member iter" << std::endl; ) 978 return *this; 979 } 980 } 981 return bigStep(); 982 } 983 984 const ast::Type * getType() override { 985 return tuple; 986 } 987 988 const ast::Type * getNext() override { 989 bool hasMember = memberIter && *memberIter; 990 return hasMember ? memberIter->getType() : nullptr; 991 } 992 993 std::deque< InitAlternative > first() const override { 994 PRINT( std::cerr << "first in TupleIterator (" << index << "/" << size << ")" << std::endl; ) 995 if ( memberIter && *memberIter ) { 996 std::deque< InitAlternative > ret = memberIter->first(); 997 for ( InitAlternative & alt : ret ) { 998 alt.designation.get_and_mutate()->designators.emplace_front( 999 ConstantExpr::from_ulong( location, index ) ); 1000 } 1001 return ret; 1002 } 1003 return {}; 921 1004 } 922 1005 }; -
src/ResolvExpr/CurrentObject.h
ra50fdfb r6e1e2d0 9 9 // Author : Rob Schluntz 10 10 // Created On : Thu Jun 8 11:07:25 2017 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sat Jul 22 09:36:48 201713 // Update Count : 311 // Last Modified By : Andrew Beach 12 // Last Modified On : Thu Apr 6 16:14:00 2023 13 // Update Count : 4 14 14 // 15 15 … … 65 65 66 66 /// Iterates members of a type by initializer 67 class MemberIterator { 68 public: 69 virtual ~MemberIterator() {} 70 71 /// Internal set position based on iterator ranges 72 virtual void setPosition( 73 std::deque< ptr< Expr > >::const_iterator it, 74 std::deque< ptr< Expr > >::const_iterator end ) = 0; 75 76 /// walks the current object using the given designators as a guide 77 void setPosition( const std::deque< ptr< Expr > > & designators ) { 78 setPosition( designators.begin(), designators.end() ); 79 } 80 81 /// retrieve the list of possible (Type,Designation) pairs for the current position in the 82 /// current object 83 virtual std::deque< InitAlternative > operator* () const = 0; 84 85 /// true if the iterator is not currently at the end 86 virtual operator bool() const = 0; 87 88 /// moves the iterator by one member in the current object 89 virtual MemberIterator & bigStep() = 0; 90 91 /// moves the iterator by one member in the current subobject 92 virtual MemberIterator & smallStep() = 0; 93 94 /// the type of the current object 95 virtual const Type * getType() = 0; 96 97 /// the type of the current subobject 98 virtual const Type * getNext() = 0; 99 100 /// helper for operator*; aggregates must add designator to each init alternative, but 101 /// adding designators in operator* creates duplicates 102 virtual std::deque< InitAlternative > first() const = 0; 103 }; 67 class MemberIterator; 104 68 105 69 /// Builds initializer lists in resolution -
src/ResolvExpr/ExplodedArg.hpp
ra50fdfb r6e1e2d0 35 35 ExplodedArg() : env(), cost( Cost::zero ), exprs() {} 36 36 ExplodedArg( const Candidate & arg, const ast::SymbolTable & symtab ); 37 37 38 38 ExplodedArg( ExplodedArg && ) = default; 39 39 ExplodedArg & operator= ( ExplodedArg && ) = default; -
src/SymTab/Autogen.cc
ra50fdfb r6e1e2d0 10 10 // Created On : Thu Mar 03 15:45:56 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Apr 27 14:39:06 201813 // Update Count : 6 312 // Last Modified On : Fri Apr 14 15:03:00 2023 13 // Update Count : 64 14 14 // 15 15 … … 211 211 } 212 212 213 bool isUnnamedBitfield( const ast::ObjectDecl * obj ) {214 return obj && obj->name.empty() && obj->bitfieldWidth;215 }216 217 213 /// inserts a forward declaration for functionDecl into declsToAdd 218 214 void addForwardDecl( FunctionDecl * functionDecl, std::list< Declaration * > & declsToAdd ) { … … 234 230 } 235 231 236 // shallow copy the pointer list for return237 std::vector<ast::ptr<ast::TypeDecl>> getGenericParams (const ast::Type * t) {238 if (auto structInst = dynamic_cast<const ast::StructInstType*>(t)) {239 return structInst->base->params;240 }241 if (auto unionInst = dynamic_cast<const ast::UnionInstType*>(t)) {242 return unionInst->base->params;243 }244 return {};245 }246 247 232 /// given type T, generate type of default ctor/dtor, i.e. function type void (*) (T *) 248 233 FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic ) { … … 256 241 ftype->parameters.push_back( dstParam ); 257 242 return ftype; 258 }259 260 /// Given type T, generate type of default ctor/dtor, i.e. function type void (*) (T &).261 ast::FunctionDecl * genDefaultFunc(const CodeLocation loc, const std::string fname, const ast::Type * paramType, bool maybePolymorphic) {262 std::vector<ast::ptr<ast::TypeDecl>> typeParams;263 if (maybePolymorphic) typeParams = getGenericParams(paramType);264 auto dstParam = new ast::ObjectDecl(loc, "_dst", new ast::ReferenceType(paramType), nullptr, {}, ast::Linkage::Cforall);265 return new ast::FunctionDecl(loc, fname, std::move(typeParams), {dstParam}, {}, new ast::CompoundStmt(loc), {}, ast::Linkage::Cforall);266 243 } 267 244 -
src/SymTab/Autogen.h
ra50fdfb r6e1e2d0 9 9 // Author : Rob Schluntz 10 10 // Created On : Sun May 17 21:53:34 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Dec 13 16:38:06 201913 // Update Count : 1 611 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Apr 14 15:06:00 2023 13 // Update Count : 17 14 14 // 15 15 … … 45 45 /// returns true if obj's name is the empty string and it has a bitfield width 46 46 bool isUnnamedBitfield( ObjectDecl * obj ); 47 bool isUnnamedBitfield( const ast::ObjectDecl * obj );48 47 49 48 /// generate the type of an assignment function for paramType. … … 55 54 FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic = true ); 56 55 57 ast::FunctionDecl * genDefaultFunc(const CodeLocation loc, const std::string fname, const ast::Type * paramType, bool maybePolymorphic = true);58 59 56 /// generate the type of a copy constructor for paramType. 60 57 /// maybePolymorphic is true if the resulting FunctionType is allowed to be polymorphic … … 67 64 template< typename OutputIterator > 68 65 Statement * genCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast = nullptr, bool forward = true ); 69 70 template< typename OutIter >71 ast::ptr< ast::Stmt > genCall(72 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,73 const CodeLocation & loc, const std::string & fname, OutIter && out,74 const ast::Type * type, const ast::Type * addCast, LoopDirection forward = LoopForward );75 66 76 67 /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Should only be called with non-array types. … … 121 112 122 113 *out++ = new ExprStmt( fExpr ); 123 124 srcParam.clearArrayIndices();125 126 return listInit;127 }128 129 /// inserts into out a generated call expression to function fname with arguments dstParam and130 /// srcParam. Should only be called with non-array types.131 /// optionally returns a statement which must be inserted prior to the containing loop, if132 /// there is one133 template< typename OutIter >134 ast::ptr< ast::Stmt > genScalarCall(135 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,136 const CodeLocation & loc, std::string fname, OutIter && out, const ast::Type * type,137 const ast::Type * addCast = nullptr138 ) {139 bool isReferenceCtorDtor = false;140 if ( dynamic_cast< const ast::ReferenceType * >( type ) && CodeGen::isCtorDtor( fname ) ) {141 // reference constructors are essentially application of the rebind operator.142 // apply & to both arguments, do not need a cast143 fname = "?=?";144 dstParam = new ast::AddressExpr{ dstParam };145 addCast = nullptr;146 isReferenceCtorDtor = true;147 }148 149 // want to be able to generate assignment, ctor, and dtor generically, so fname is one of150 // "?=?", "?{}", or "^?{}"151 ast::UntypedExpr * fExpr = new ast::UntypedExpr{ loc, new ast::NameExpr{ loc, fname } };152 153 if ( addCast ) {154 // cast to T& with qualifiers removed, so that qualified objects can be constructed and155 // destructed with the same functions as non-qualified objects. Unfortunately, lvalue156 // is considered a qualifier - for AddressExpr to resolve, its argument must have an157 // lvalue-qualified type, so remove all qualifiers except lvalue.158 // xxx -- old code actually removed lvalue too...159 ast::ptr< ast::Type > guard = addCast; // prevent castType from mutating addCast160 ast::ptr< ast::Type > castType = addCast;161 ast::remove_qualifiers(162 castType,163 ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Atomic );164 dstParam = new ast::CastExpr{ dstParam, new ast::ReferenceType{ castType } };165 }166 fExpr->args.emplace_back( dstParam );167 168 ast::ptr<ast::Stmt> listInit = srcParam.buildListInit( fExpr );169 170 // fetch next set of arguments171 ++srcParam;172 173 // return if adding reference fails -- will happen on default ctor and dtor174 if ( isReferenceCtorDtor && ! srcParam.addReference() ) return listInit;175 176 std::vector< ast::ptr< ast::Expr > > args = *srcParam;177 splice( fExpr->args, args );178 179 *out++ = new ast::ExprStmt{ loc, fExpr };180 114 181 115 srcParam.clearArrayIndices(); … … 248 182 } 249 183 250 /// Store in out a loop which calls fname on each element of the array with srcParam and251 /// dstParam as arguments. If forward is true, loop goes from 0 to N-1, else N-1 to 0252 template< typename OutIter >253 void genArrayCall(254 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,255 const CodeLocation & loc, const std::string & fname, OutIter && out,256 const ast::ArrayType * array, const ast::Type * addCast = nullptr,257 LoopDirection forward = LoopForward258 ) {259 static UniqueName indexName( "_index" );260 261 // for a flexible array member nothing is done -- user must define own assignment262 if ( ! array->dimension ) return;263 264 if ( addCast ) {265 // peel off array layer from cast266 addCast = strict_dynamic_cast< const ast::ArrayType * >( addCast )->base;267 }268 269 ast::ptr< ast::Expr > begin, end;270 std::string cmp, update;271 272 if ( forward ) {273 // generate: for ( int i = 0; i < N; ++i )274 begin = ast::ConstantExpr::from_int( loc, 0 );275 end = array->dimension;276 cmp = "?<?";277 update = "++?";278 } else {279 // generate: for ( int i = N-1; i >= 0; --i )280 begin = ast::UntypedExpr::createCall( loc, "?-?",281 { array->dimension, ast::ConstantExpr::from_int( loc, 1 ) } );282 end = ast::ConstantExpr::from_int( loc, 0 );283 cmp = "?>=?";284 update = "--?";285 }286 287 ast::ptr< ast::DeclWithType > index = new ast::ObjectDecl{288 loc, indexName.newName(), new ast::BasicType{ ast::BasicType::SignedInt },289 new ast::SingleInit{ loc, begin } };290 ast::ptr< ast::Expr > indexVar = new ast::VariableExpr{ loc, index };291 292 ast::ptr< ast::Expr > cond = ast::UntypedExpr::createCall(293 loc, cmp, { indexVar, end } );294 295 ast::ptr< ast::Expr > inc = ast::UntypedExpr::createCall(296 loc, update, { indexVar } );297 298 ast::ptr< ast::Expr > dstIndex = ast::UntypedExpr::createCall(299 loc, "?[?]", { dstParam, indexVar } );300 301 // srcParam must keep track of the array indices to build the source parameter and/or302 // array list initializer303 srcParam.addArrayIndex( indexVar, array->dimension );304 305 // for stmt's body, eventually containing call306 ast::CompoundStmt * body = new ast::CompoundStmt{ loc };307 ast::ptr< ast::Stmt > listInit = genCall(308 srcParam, dstIndex, loc, fname, std::back_inserter( body->kids ), array->base, addCast,309 forward );310 311 // block containing the stmt and index variable312 ast::CompoundStmt * block = new ast::CompoundStmt{ loc };313 block->push_back( new ast::DeclStmt{ loc, index } );314 if ( listInit ) { block->push_back( listInit ); }315 block->push_back( new ast::ForStmt{ loc, {}, cond, inc, body } );316 317 *out++ = block;318 }319 320 184 template< typename OutputIterator > 321 185 Statement * genCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast, bool forward ) { … … 325 189 } else { 326 190 return genScalarCall( srcParam, dstParam, fname, out, type, addCast ); 327 }328 }329 330 template< typename OutIter >331 ast::ptr< ast::Stmt > genCall(332 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,333 const CodeLocation & loc, const std::string & fname, OutIter && out,334 const ast::Type * type, const ast::Type * addCast, LoopDirection forward335 ) {336 if ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) {337 genArrayCall(338 srcParam, dstParam, loc, fname, std::forward< OutIter >(out), at, addCast,339 forward );340 return {};341 } else {342 return genScalarCall(343 srcParam, dstParam, loc, fname, std::forward< OutIter >( out ), type, addCast );344 191 } 345 192 } … … 379 226 } 380 227 381 static inline ast::ptr< ast::Stmt > genImplicitCall(382 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,383 const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * obj,384 LoopDirection forward = LoopForward385 ) {386 // unnamed bit fields are not copied as they cannot be accessed387 if ( isUnnamedBitfield( obj ) ) return {};388 389 ast::ptr< ast::Type > addCast;390 if ( (fname == "?{}" || fname == "^?{}") && ( ! obj || ( obj && ! obj->bitfieldWidth ) ) ) {391 assert( dstParam->result );392 addCast = dstParam->result;393 }394 395 std::vector< ast::ptr< ast::Stmt > > stmts;396 genCall(397 srcParam, dstParam, loc, fname, back_inserter( stmts ), obj->type, addCast, forward );398 399 if ( stmts.empty() ) {400 return {};401 } else if ( stmts.size() == 1 ) {402 const ast::Stmt * callStmt = stmts.front();403 if ( addCast ) {404 // implicitly generated ctor/dtor calls should be wrapped so that later passes are405 // aware they were generated.406 callStmt = new ast::ImplicitCtorDtorStmt{ callStmt->location, callStmt };407 }408 return callStmt;409 } else {410 assert( false );411 return {};412 }413 }414 228 } // namespace SymTab 415 229 -
src/SymTab/module.mk
ra50fdfb r6e1e2d0 20 20 SymTab/FixFunction.cc \ 21 21 SymTab/FixFunction.h \ 22 SymTab/GenImplicitCall.cpp \ 23 SymTab/GenImplicitCall.hpp \ 22 24 SymTab/Indexer.cc \ 23 25 SymTab/Indexer.h \ -
src/Validate/Autogen.cpp
ra50fdfb r6e1e2d0 39 39 #include "InitTweak/GenInit.h" // for fixReturnStatements 40 40 #include "InitTweak/InitTweak.h" // for isAssignment, isCopyConstructor 41 #include "SymTab/GenImplicitCall.hpp" // for genImplicitCall 41 42 #include "SymTab/Mangler.h" // for Mangler 42 43 #include "CompilationState.h" … … 423 424 for ( unsigned int index = 0 ; index < fields ; ++index ) { 424 425 auto member = aggr->members[index].strict_as<ast::DeclWithType>(); 425 if ( SymTab::isUnnamedBitfield(426 if ( ast::isUnnamedBitfield( 426 427 dynamic_cast<const ast::ObjectDecl *>( member ) ) ) { 427 428 if ( index == fields - 1 ) { … … 599 600 // Not sure why it could be null. 600 601 // Don't make a function for a parameter that is an unnamed bitfield. 601 if ( nullptr == field || SymTab::isUnnamedBitfield( field ) ) {602 if ( nullptr == field || ast::isUnnamedBitfield( field ) ) { 602 603 continue; 603 604 // Matching Parameter: Initialize the field by copy. -
src/main.cc
ra50fdfb r6e1e2d0 9 9 // Author : Peter Buhr and Rob Schluntz 10 10 // Created On : Fri May 15 23:12:02 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Thr Feb 16 10:08:00202313 // Update Count : 68 011 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 10 21:12:17 2023 13 // Update Count : 682 14 14 // 15 15 … … 32 32 33 33 #include "AST/Convert.hpp" 34 #include "AST/Util.hpp" // for checkInvariants 34 35 #include "CompilationState.h" 35 36 #include "../config.h" // for CFA_LIBDIR … … 102 103 } 103 104 104 #define PASS( name, pass ) \ 105 // Helpers for checkInvariant: 106 void checkInvariants( std::list< Declaration * > & ) {} 107 using ast::checkInvariants; 108 109 #define PASS( name, pass, unit, ... ) \ 105 110 if ( errorp ) { cerr << name << endl; } \ 106 111 NewPass(name); \ 107 112 Stats::Time::StartBlock(name); \ 108 pass; \ 109 Stats::Time::StopBlock(); 113 pass(unit,##__VA_ARGS__); \ 114 Stats::Time::StopBlock(); \ 115 if ( invariant ) { \ 116 checkInvariants(unit); \ 117 } 118 119 #define DUMP( cond, unit ) \ 120 if ( cond ) { \ 121 dump(unit); \ 122 return EXIT_SUCCESS; \ 123 } 110 124 111 125 static bool waiting_for_gdb = false; // flag to set cfa-cpp to wait for gdb on start … … 298 312 transUnit = buildUnit(); 299 313 300 if ( astp ) { 301 dump( std::move( transUnit ) ); 302 return EXIT_SUCCESS; 303 } // if 314 DUMP( astp, std::move( transUnit ) ); 304 315 305 316 Stats::Time::StopBlock(); … … 310 321 } 311 322 312 PASS( "Hoist Type Decls", Validate::hoistTypeDecls( transUnit ) ); 313 // Hoist Type Decls pulls some declarations out of contexts where 314 // locations are not tracked. Perhaps they should be, but for now 315 // the full fill solves it. 316 forceFillCodeLocations( transUnit ); 317 318 PASS( "Translate Exception Declarations", ControlStruct::translateExcept( transUnit ) ); 319 if ( exdeclp ) { 320 dump( std::move( transUnit ) ); 321 return EXIT_SUCCESS; 322 } 323 324 PASS( "Verify Ctor, Dtor & Assign", Validate::verifyCtorDtorAssign( transUnit ) ); 325 PASS( "Replace Typedefs", Validate::replaceTypedef( transUnit ) ); 326 PASS( "Fix Return Types", Validate::fixReturnTypes( transUnit ) ); 327 PASS( "Enum and Pointer Decay", Validate::decayEnumsAndPointers( transUnit ) ); 328 329 PASS( "Link Reference To Types", Validate::linkReferenceToTypes( transUnit ) ); 330 331 PASS( "Fix Qualified Types", Validate::fixQualifiedTypes( transUnit ) ); 332 PASS( "Hoist Struct", Validate::hoistStruct( transUnit ) ); 333 PASS( "Eliminate Typedef", Validate::eliminateTypedef( transUnit ) ); 334 PASS( "Validate Generic Parameters", Validate::fillGenericParameters( transUnit ) ); 335 PASS( "Translate Dimensions", Validate::translateDimensionParameters( transUnit ) ); 336 PASS( "Check Function Returns", Validate::checkReturnStatements( transUnit ) ); 337 PASS( "Fix Return Statements", InitTweak::fixReturnStatements( transUnit ) ); 338 PASS( "Implement Concurrent Keywords", Concurrency::implementKeywords( transUnit ) ); 339 PASS( "Forall Pointer Decay", Validate::decayForallPointers( transUnit ) ); 340 PASS( "Implement Waituntil", Concurrency::generateWaitUntil( transUnit ) ); 341 PASS( "Hoist Control Declarations", ControlStruct::hoistControlDecls( transUnit ) ); 342 343 PASS( "Generate Autogen Routines", Validate::autogenerateRoutines( transUnit ) ); 344 345 PASS( "Implement Actors", Concurrency::implementActors( transUnit ) ); 346 PASS( "Implement Virtual Destructors", Virtual::implementVirtDtors(transUnit) ); 347 PASS( "Implement Mutex", Concurrency::implementMutex( transUnit ) ); 348 PASS( "Implement Thread Start", Concurrency::implementThreadStarter( transUnit ) ); 349 PASS( "Compound Literal", Validate::handleCompoundLiterals( transUnit ) ); 350 PASS( "Set Length From Initializer", Validate::setLengthFromInitializer( transUnit ) ); 351 PASS( "Find Global Decls", Validate::findGlobalDecls( transUnit ) ); 352 PASS( "Fix Label Address", Validate::fixLabelAddresses( transUnit ) ); 323 PASS( "Hoist Type Decls", Validate::hoistTypeDecls, transUnit ); 324 325 PASS( "Translate Exception Declarations", ControlStruct::translateExcept, transUnit ); 326 DUMP( exdeclp, std::move( transUnit ) ); 327 PASS( "Verify Ctor, Dtor & Assign", Validate::verifyCtorDtorAssign, transUnit ); 328 PASS( "Replace Typedefs", Validate::replaceTypedef, transUnit ); 329 PASS( "Fix Return Types", Validate::fixReturnTypes, transUnit ); 330 PASS( "Enum and Pointer Decay", Validate::decayEnumsAndPointers, transUnit ); 331 332 PASS( "Link Reference To Types", Validate::linkReferenceToTypes, transUnit ); 333 334 PASS( "Fix Qualified Types", Validate::fixQualifiedTypes, transUnit ); 335 PASS( "Hoist Struct", Validate::hoistStruct, transUnit ); 336 PASS( "Eliminate Typedef", Validate::eliminateTypedef, transUnit ); 337 PASS( "Validate Generic Parameters", Validate::fillGenericParameters, transUnit ); 338 PASS( "Translate Dimensions", Validate::translateDimensionParameters, transUnit ); 339 PASS( "Check Function Returns", Validate::checkReturnStatements, transUnit ); 340 PASS( "Fix Return Statements", InitTweak::fixReturnStatements, transUnit ); 341 PASS( "Implement Concurrent Keywords", Concurrency::implementKeywords, transUnit ); 342 PASS( "Forall Pointer Decay", Validate::decayForallPointers, transUnit ); 343 PASS( "Implement Waituntil", Concurrency::generateWaitUntil, transUnit ); 344 PASS( "Hoist Control Declarations", ControlStruct::hoistControlDecls, transUnit ); 345 346 PASS( "Generate Autogen Routines", Validate::autogenerateRoutines, transUnit ); 347 348 PASS( "Implement Actors", Concurrency::implementActors, transUnit ); 349 PASS( "Implement Virtual Destructors", Virtual::implementVirtDtors, transUnit ); 350 PASS( "Implement Mutex", Concurrency::implementMutex, transUnit ); 351 PASS( "Implement Thread Start", Concurrency::implementThreadStarter, transUnit ); 352 PASS( "Compound Literal", Validate::handleCompoundLiterals, transUnit ); 353 PASS( "Set Length From Initializer", Validate::setLengthFromInitializer, transUnit ); 354 PASS( "Find Global Decls", Validate::findGlobalDecls, transUnit ); 355 PASS( "Fix Label Address", Validate::fixLabelAddresses, transUnit ); 353 356 354 357 if ( symtabp ) { … … 361 364 } // if 362 365 363 if ( validp ) { 364 dump( std::move( transUnit ) ); 365 return EXIT_SUCCESS; 366 } // if 367 368 PASS( "Translate Throws", ControlStruct::translateThrows( transUnit ) ); 369 PASS( "Fix Labels", ControlStruct::fixLabels( transUnit ) ); 370 PASS( "Fix Names", CodeGen::fixNames( transUnit ) ); 371 PASS( "Gen Init", InitTweak::genInit( transUnit ) ); 372 PASS( "Expand Member Tuples" , Tuples::expandMemberTuples( transUnit ) ); 366 DUMP( validp, std::move( transUnit ) ); 367 368 PASS( "Translate Throws", ControlStruct::translateThrows, transUnit ); 369 PASS( "Fix Labels", ControlStruct::fixLabels, transUnit ); 370 PASS( "Fix Names", CodeGen::fixNames, transUnit ); 371 PASS( "Gen Init", InitTweak::genInit, transUnit ); 372 PASS( "Expand Member Tuples" , Tuples::expandMemberTuples, transUnit ); 373 373 374 374 if ( libcfap ) { … … 382 382 } // if 383 383 384 if ( bresolvep ) { 385 dump( std::move( transUnit ) ); 386 return EXIT_SUCCESS; 387 } // if 384 DUMP( bresolvep, std::move( transUnit ) ); 388 385 389 386 if ( resolvprotop ) { … … 392 389 } // if 393 390 394 PASS( "Resolve", ResolvExpr::resolve( transUnit ) ); 395 if ( exprp ) { 396 dump( std::move( transUnit ) ); 397 return EXIT_SUCCESS; 398 } // if 399 400 forceFillCodeLocations( transUnit ); 401 402 PASS( "Fix Init", InitTweak::fix(transUnit, buildingLibrary())); 391 PASS( "Resolve", ResolvExpr::resolve, transUnit ); 392 DUMP( exprp, std::move( transUnit ) ); 393 394 PASS( "Fix Init", InitTweak::fix, transUnit, buildingLibrary() ); 403 395 404 396 // fix ObjectDecl - replaces ConstructorInit nodes 405 if ( ctorinitp ) { 406 dump( std::move( transUnit ) ); 407 return EXIT_SUCCESS; 408 } // if 397 DUMP( ctorinitp, std::move( transUnit ) ); 409 398 410 399 // Currently not working due to unresolved issues with UniqueExpr 411 PASS( "Expand Unique Expr", Tuples::expandUniqueExpr ( transUnit )); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused412 413 PASS( "Translate Tries", ControlStruct::translateTries ( transUnit ));414 PASS( "Gen Waitfor", Concurrency::generateWaitFor ( transUnit ));400 PASS( "Expand Unique Expr", Tuples::expandUniqueExpr, transUnit ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused 401 402 PASS( "Translate Tries", ControlStruct::translateTries, transUnit ); 403 PASS( "Gen Waitfor", Concurrency::generateWaitFor, transUnit ); 415 404 416 405 // Needs to happen before tuple types are expanded. 417 PASS( "Convert Specializations", GenPoly::convertSpecializations( transUnit ) ); 418 419 PASS( "Expand Tuples", Tuples::expandTuples( transUnit ) ); 420 421 if ( tuplep ) { 422 dump( std::move( transUnit ) ); 423 return EXIT_SUCCESS; 424 } // if 406 PASS( "Convert Specializations", GenPoly::convertSpecializations, transUnit ); 407 408 PASS( "Expand Tuples", Tuples::expandTuples, transUnit ); 409 DUMP( tuplep, std::move( transUnit ) ); 425 410 426 411 // Must come after Translate Tries. 427 PASS( "Virtual Expand Casts", Virtual::expandCasts( transUnit ) ); 428 429 PASS( "Instantiate Generics", GenPoly::instantiateGeneric( transUnit ) ); 430 if ( genericsp ) { 431 dump( std::move( transUnit ) ); 432 return EXIT_SUCCESS; 433 } // if 434 435 PASS( "Convert L-Value", GenPoly::convertLvalue( transUnit ) ); 412 PASS( "Virtual Expand Casts", Virtual::expandCasts, transUnit ); 413 414 PASS( "Instantiate Generics", GenPoly::instantiateGeneric, transUnit ); 415 DUMP( genericsp, std::move( transUnit ) ); 416 417 PASS( "Convert L-Value", GenPoly::convertLvalue, transUnit ); 436 418 437 419 translationUnit = convert( std::move( transUnit ) ); 438 420 439 if ( bboxp ) { 440 dump( translationUnit ); 441 return EXIT_SUCCESS; 442 } // if 443 PASS( "Box", GenPoly::box( translationUnit ) ); 444 445 PASS( "Link-Once", CodeGen::translateLinkOnce( translationUnit ) ); 421 DUMP( bboxp, translationUnit ); 422 PASS( "Box", GenPoly::box, translationUnit ); 423 424 PASS( "Link-Once", CodeGen::translateLinkOnce, translationUnit ); 446 425 447 426 // Code has been lowered to C, now we can start generation. 448 427 449 if ( bcodegenp ) { 450 dump( translationUnit ); 451 return EXIT_SUCCESS; 452 } // if 428 DUMP( bcodegenp, translationUnit ); 453 429 454 430 if ( optind < argc ) { // any commands after the flags and input file ? => output file name … … 457 433 458 434 CodeTools::fillLocations( translationUnit ); 459 PASS( "Code Gen", CodeGen::generate ( translationUnit, *output, ! genproto, prettycodegenp, true, linemarks ));435 PASS( "Code Gen", CodeGen::generate, translationUnit, *output, ! genproto, prettycodegenp, true, linemarks ); 460 436 461 437 CodeGen::FixMain::fix( translationUnit, *output, … … 505 481 506 482 507 static const char optstring[] = ":c:gh lLmNnpdP:S:twW:D:";483 static const char optstring[] = ":c:ghilLmNnpdP:S:twW:D:"; 508 484 509 485 enum { PreludeDir = 128 }; … … 512 488 { "gdb", no_argument, nullptr, 'g' }, 513 489 { "help", no_argument, nullptr, 'h' }, 490 { "invariant", no_argument, nullptr, 'i' }, 514 491 { "libcfa", no_argument, nullptr, 'l' }, 515 492 { "linemarks", no_argument, nullptr, 'L' }, 516 { "no-main", no_argument, 0, 'm' },493 { "no-main", no_argument, nullptr, 'm' }, 517 494 { "no-linemarks", no_argument, nullptr, 'N' }, 518 495 { "no-prelude", no_argument, nullptr, 'n' }, … … 533 510 "wait for gdb to attach", // -g 534 511 "print translator help message", // -h 512 "invariant checking during AST passes", // -i 535 513 "generate libcfa.c", // -l 536 514 "generate line marks", // -L … … 626 604 usage( argv ); // no return 627 605 break; 606 case 'i': // invariant checking 607 invariant = true; 608 break; 628 609 case 'l': // generate libcfa.c 629 610 libcfap = true;
Note:
See TracChangeset
for help on using the changeset viewer.