Changeset 87b5bf0
- Timestamp:
- Jun 29, 2016, 2:30:12 PM (7 years ago)
- Branches:
- ADT, aaron-thesis, arm-eh, cleanup-dtors, ctor, deferred_resn, demangler, enum, forall-pointer-decay, gc_noraii, jacob/cs343-translation, jenkins-sandbox, master, memory, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
- Children:
- e64365c
- Parents:
- 7305915 (diff), 2fb2ad5 (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:
-
- 9 added
- 27 edited
Legend:
- Unmodified
- Added
- Removed
-
src/CodeGen/CodeGenerator.cc
r7305915 r87b5bf0 48 48 } 49 49 50 ostream & CodeGenerator::Indenter::operator()( ostream & output ) {50 ostream & CodeGenerator::Indenter::operator()( ostream & output ) const { 51 51 return output << string( cg.cur_indent, ' ' ); 52 52 } 53 53 54 ostream & operator<<( ostream & output, CodeGenerator::Indenter &indent ) {54 ostream & operator<<( ostream & output, const CodeGenerator::Indenter &indent ) { 55 55 return indent( output ); 56 56 } 57 57 58 CodeGenerator::CodeGenerator( std::ostream &os ) : indent( *this), cur_indent( 0 ), insideFunction( false ), output( os ) { } 58 CodeGenerator::LabelPrinter & CodeGenerator::LabelPrinter::operator()( std::list< Label > & l ) { 59 labels = &l; 60 return *this; 61 } 62 63 ostream & operator<<( ostream & output, CodeGenerator::LabelPrinter &printLabels ) { 64 std::list< Label > & labs = *printLabels.labels; 65 // l.unique(); // assumes a sorted list. Why not use set? Does order matter? 66 for ( Label & l : labs ) { 67 output << l.get_name() + ": "; 68 printLabels.cg.genAttributes( l.get_attributes() ); 69 } 70 return output; 71 } 72 73 CodeGenerator::CodeGenerator( std::ostream &os ) : indent( *this), cur_indent( 0 ), insideFunction( false ), output( os ), printLabels( *this ) { } 59 74 60 75 CodeGenerator::CodeGenerator( std::ostream &os, std::string init, int indentation, bool infunp ) 61 : indent( *this), cur_indent( indentation ), insideFunction( infunp ), output( os ) {76 : indent( *this), cur_indent( indentation ), insideFunction( infunp ), output( os ), printLabels( *this ) { 62 77 //output << std::string( init ); 63 78 } 64 79 65 80 CodeGenerator::CodeGenerator( std::ostream &os, char *init, int indentation, bool infunp ) 66 : indent( *this ), cur_indent( indentation ), insideFunction( infunp ), output( os ) {81 : indent( *this ), cur_indent( indentation ), insideFunction( infunp ), output( os ), printLabels( *this ) { 67 82 //output << std::string( init ); 68 83 } … … 735 750 void CodeGenerator::visit( ReturnStmt *returnStmt ) { 736 751 output << "return "; 737 738 // xxx -- check for null expression; 739 if ( returnStmt->get_expr() ) { 740 returnStmt->get_expr()->accept( *this ); 741 } // if 752 maybeAccept( returnStmt->get_expr(), *this ); 742 753 output << ";"; 743 754 } … … 799 810 output << ";"; 800 811 } // if 801 }802 803 std::string CodeGenerator::printLabels( std::list< Label > &l ) {804 std::string str( "" );805 l.unique(); // assumes a sorted list. Why not use set?806 807 for ( std::list< Label >::iterator i = l.begin(); i != l.end(); i++ )808 str += *i + ": ";809 810 return str;811 812 } 812 813 -
src/CodeGen/CodeGenerator.h
r7305915 r87b5bf0 94 94 Indenter(CodeGenerator &cg) : cg(cg) {} 95 95 CodeGenerator & cg; 96 std::ostream& operator()(std::ostream & os); 96 std::ostream& operator()(std::ostream & os) const; 97 }; 98 99 struct LabelPrinter { 100 LabelPrinter(CodeGenerator &cg) : cg(cg), labels( 0 ) {} 101 LabelPrinter & operator()( std::list< Label > & l ); 102 CodeGenerator & cg; 103 std::list< Label > * labels; 97 104 }; 98 105 … … 108 115 bool insideFunction; 109 116 std::ostream &output; 117 LabelPrinter printLabels; 110 118 111 119 void printDesignators( std::list< Expression * > & ); 112 static std::string printLabels ( std::list < Label > & );113 120 void handleStorageClass( Declaration *decl ); 114 121 void handleAggregate( AggregateDecl *aggDecl ); -
src/ControlStruct/LabelFixer.cc
r7305915 r87b5bf0 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // LabelFixer.cc -- 7 // LabelFixer.cc -- 8 8 // 9 9 // Author : Rodolfo G. Esteves … … 86 86 87 87 88 // sets the definition of the labelTable entry to be the provided 88 // sets the definition of the labelTable entry to be the provided 89 89 // statement for every label in the list parameter. Happens for every kind of statement 90 90 Label LabelFixer::setLabelsDef( std::list< Label > &llabel, Statement *definition ) { … … 95 95 96 96 for ( std::list< Label >::iterator i = llabel.begin(); i != llabel.end(); i++ ) { 97 if ( labelTable.find( *i ) == labelTable.end() ) { 97 Label & l = *i; 98 l.set_statement( definition ); // attach statement to the label to be used later 99 if ( labelTable.find( l ) == labelTable.end() ) { 98 100 // all labels on this statement need to use the same entry, so this should only be created once 99 101 // undefined and unused until now, add an entry 100 labelTable[ *i] = e;101 } else if ( labelTable[ *i]->defined() ) {102 labelTable[ l ] = e; 103 } else if ( labelTable[ l ]->defined() ) { 102 104 // defined twice, error 103 throw SemanticError( "Duplicate definition of label: " + *i);105 throw SemanticError( "Duplicate definition of label: " + l.get_name() ); 104 106 } else { 105 107 // used previously, but undefined until now -> link with this entry 106 delete labelTable[ *i];107 labelTable[ *i] = e;108 delete labelTable[ l ]; 109 labelTable[ l ] = e; 108 110 } // if 109 111 } // for 110 112 111 // produce one of the labels attached to this statement to be 113 // produce one of the labels attached to this statement to be 112 114 // temporarily used as the canonical label 113 115 return labelTable[ llabel.front() ]->get_label(); 114 116 } 115 117 116 // A label was used, add it otthe table if it isn't already there118 // A label was used, add it to the table if it isn't already there 117 119 template< typename UsageNode > 118 120 void LabelFixer::setLabelsUsg( Label orgValue, UsageNode *use ) { … … 130 132 for ( std::map< Label, Entry * >::iterator i = labelTable.begin(); i != labelTable.end(); ++i ) { 131 133 if ( ! i->second->defined() ) { 132 throw SemanticError( "Use of undefined label: " + i->first );134 throw SemanticError( "Use of undefined label: " + i->first.get_name() ); 133 135 } 134 136 (*ret)[ i->first ] = i->second->get_definition(); -
src/ControlStruct/LabelFixer.h
r7305915 r87b5bf0 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // LabelFixer.h -- 7 // LabelFixer.h -- 8 8 // 9 9 // Author : Rodolfo G. Esteves … … 20 20 #include "SynTree/SynTree.h" 21 21 #include "SynTree/Visitor.h" 22 #include "SynTree/Label.h" 22 23 #include "LabelGenerator.h" 23 24 24 #include <map> 25 25 … … 74 74 75 75 private: 76 Label label; 76 Label label; 77 77 Statement *definition; 78 78 }; 79 79 80 80 std::map < Label, Entry *> labelTable; 81 81 LabelGenerator *generator; -
src/ControlStruct/LabelGenerator.cc
r7305915 r87b5bf0 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // LabelGenerator.cc -- 7 // LabelGenerator.cc -- 8 8 // 9 9 // Author : Rodolfo G. Esteves … … 18 18 19 19 #include "LabelGenerator.h" 20 #include "SynTree/Label.h" 21 #include "SynTree/Attribute.h" 20 22 21 23 namespace ControlStruct { … … 33 35 os << "__L" << current++ << "__" << suffix; 34 36 std::string ret = os.str(); 35 return Label( ret ); 37 Label l( ret ); 38 l.get_attributes().push_back( new Attribute("unused") ); 39 return l; 36 40 } 37 41 } // namespace ControlStruct -
src/ControlStruct/MLEMutator.cc
r7305915 r87b5bf0 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // MLEMutator.cc -- 7 // MLEMutator.cc -- 8 8 // 9 9 // Author : Rodolfo G. Esteves … … 14 14 // 15 15 16 // NOTE: There are two known subtle differences from the code that uC++ 16 // NOTE: There are two known subtle differences from the code that uC++ 17 17 // generates for the same input 18 18 // -CFA puts the break label inside at the end of a switch, uC++ puts it after … … 27 27 #include "SynTree/Statement.h" 28 28 #include "SynTree/Expression.h" 29 #include "SynTree/Attribute.h" 29 30 30 31 namespace ControlStruct { … … 33 34 targetTable = 0; 34 35 } 35 36 // break labels have to come after the statement they break out of, 36 namespace { 37 Statement * isLoop( Statement * stmt ) { return dynamic_cast< WhileStmt * >( stmt ) ? stmt : dynamic_cast< ForStmt * >( stmt ) ? stmt : 0; } 38 } 39 40 // break labels have to come after the statement they break out of, 37 41 // so mutate a statement, then if they inform us through the breakLabel field 38 // tha they need a place to jump to on a break statement, add the break label 42 // tha they need a place to jump to on a break statement, add the break label 39 43 // to the body of statements 40 44 void MLEMutator::fixBlock( std::list< Statement * > &kids ) { … … 44 48 if ( ! get_breakLabel().empty() ) { 45 49 std::list< Statement * >::iterator next = k+1; 46 if ( next == kids.end() ) { 47 std::list<Label> ls; ls.push_back( get_breakLabel() ); 48 kids.push_back( new NullStmt( ls ) ); 49 } else { 50 (*next)->get_labels().push_back( get_breakLabel() ); 51 } 52 50 std::list<Label> ls; ls.push_back( get_breakLabel() ); 51 kids.insert( next, new NullStmt( ls ) ); 53 52 set_breakLabel(""); 54 53 } // if … … 60 59 if ( labeledBlock ) { 61 60 Label brkLabel = generator->newLabel("blockBreak"); 62 enclosing Blocks.push_back( Entry( cmpndStmt, brkLabel ) );61 enclosingControlStructures.push_back( Entry( cmpndStmt, brkLabel ) ); 63 62 } // if 64 63 … … 69 68 70 69 if ( labeledBlock ) { 71 assert( ! enclosing Blocks.empty() );72 if ( ! enclosing Blocks.back().useBreakExit().empty() ) {73 set_breakLabel( enclosing Blocks.back().useBreakExit() );74 } 75 enclosing Blocks.pop_back();70 assert( ! enclosingControlStructures.empty() ); 71 if ( ! enclosingControlStructures.back().useBreakExit().empty() ) { 72 set_breakLabel( enclosingControlStructures.back().useBreakExit() ); 73 } 74 enclosingControlStructures.pop_back(); 76 75 } // if 77 76 … … 81 80 template< typename LoopClass > 82 81 Statement *MLEMutator::handleLoopStmt( LoopClass *loopStmt ) { 83 // remember this as the most recent enclosing loop, then mutate 82 // remember this as the most recent enclosing loop, then mutate 84 83 // the body of the loop -- this will determine whether brkLabel 85 84 // and contLabel are used with branch statements … … 87 86 Label brkLabel = generator->newLabel("loopBreak"); 88 87 Label contLabel = generator->newLabel("loopContinue"); 89 enclosing Loops.push_back( Entry( loopStmt, brkLabel, contLabel ) );88 enclosingControlStructures.push_back( Entry( loopStmt, brkLabel, contLabel ) ); 90 89 loopStmt->set_body ( loopStmt->get_body()->acceptMutator( *this ) ); 91 90 92 91 // sanity check that the enclosing loops have been popped correctly 93 Entry &e = enclosing Loops.back();92 Entry &e = enclosingControlStructures.back(); 94 93 assert ( e == loopStmt ); 95 94 … … 97 96 // two labels, if they are used. 98 97 loopStmt->set_body( mutateLoop( loopStmt->get_body(), e ) ); 99 enclosing Loops.pop_back();98 enclosingControlStructures.pop_back(); 100 99 101 100 return loopStmt; … … 111 110 template< typename SwitchClass > 112 111 Statement *MLEMutator::handleSwitchStmt( SwitchClass *switchStmt ) { 113 // generate a label for breaking out of a labeled switch 112 // generate a label for breaking out of a labeled switch 114 113 Label brkLabel = generator->newLabel("switchBreak"); 115 enclosing Switches.push_back( Entry(switchStmt, brkLabel) );116 mutateAll( switchStmt->get_branches(), *this ); 117 118 Entry &e = enclosing Switches.back();114 enclosingControlStructures.push_back( Entry(switchStmt, brkLabel) ); 115 mutateAll( switchStmt->get_branches(), *this ); 116 117 Entry &e = enclosingControlStructures.back(); 119 118 assert ( e == switchStmt ); 120 119 121 120 // only generate break label if labeled break is used 122 121 if (e.isBreakUsed()) { 123 // for the purposes of keeping switch statements uniform (i.e. all statements that are 124 // direct children of a switch should be CastStmts), append the exit label + break to the 122 // for the purposes of keeping switch statements uniform (i.e. all statements that are 123 // direct children of a switch should be CastStmts), append the exit label + break to the 125 124 // last case statement; create a default case if there are no cases 126 125 std::list< Statement * > &branches = switchStmt->get_branches(); … … 131 130 if ( CaseStmt * c = dynamic_cast< CaseStmt * >( branches.back() ) ) { 132 131 std::list<Label> temp; temp.push_back( brkLabel ); 133 c->get_statements().push_back( new BranchStmt( temp, Label(" "), BranchStmt::Break ) );132 c->get_statements().push_back( new BranchStmt( temp, Label("brkLabel"), BranchStmt::Break ) ); 134 133 } else assert(0); // as of this point, all branches of a switch are still CaseStmts 135 134 } 136 135 137 assert ( enclosing Switches.back() == switchStmt );138 enclosing Switches.pop_back();136 assert ( enclosingControlStructures.back() == switchStmt ); 137 enclosingControlStructures.pop_back(); 139 138 return switchStmt; 140 139 } … … 143 142 std::string originalTarget = branchStmt->get_originalTarget(); 144 143 145 if ( branchStmt->get_type() == BranchStmt::Goto ) 144 std::list< Entry >::reverse_iterator targetEntry; 145 if ( branchStmt->get_type() == BranchStmt::Goto ) { 146 146 return branchStmt; 147 148 // test if continue target is a loop 149 if ( branchStmt->get_type() == BranchStmt::Continue) { 150 if ( enclosingLoops.empty() ) { 151 throw SemanticError( "'continue' outside a loop" ); 152 } else if ( branchStmt->get_target() != "" && std::find( enclosingLoops.begin(), enclosingLoops.end(), (*targetTable)[branchStmt->get_target()] ) == enclosingLoops.end() ) { 153 throw SemanticError( "'continue' target label must be an enclosing loop: " + originalTarget ); 154 } 155 } 156 157 if ( branchStmt->get_type() == BranchStmt::Break && (enclosingLoops.empty() && enclosingSwitches.empty() && enclosingBlocks.empty() ) ) 158 throw SemanticError( "'break' outside a loop or switch" ); 159 160 if ( branchStmt->get_target() == "" ) return branchStmt; 161 162 if ( targetTable->find( branchStmt->get_target() ) == targetTable->end() ) 147 } else if ( branchStmt->get_type() == BranchStmt::Continue) { 148 // continue target must be a loop 149 if ( branchStmt->get_target() == "" ) { 150 targetEntry = std::find_if( enclosingControlStructures.rbegin(), enclosingControlStructures.rend(), [](Entry &e) { return isLoop( e.get_controlStructure() ); } ); 151 } else { 152 // labelled continue - lookup label in table ot find attached control structure 153 targetEntry = std::find( enclosingControlStructures.rbegin(), enclosingControlStructures.rend(), (*targetTable)[branchStmt->get_target()] ); 154 } 155 if ( targetEntry == enclosingControlStructures.rend() || ! isLoop( targetEntry->get_controlStructure() ) ) { 156 throw SemanticError( "'continue' target must be an enclosing loop: " + originalTarget ); 157 } 158 } else if ( branchStmt->get_type() == BranchStmt::Break ) { 159 if ( enclosingControlStructures.empty() ) throw SemanticError( "'break' outside a loop, switch, or labelled block" ); 160 targetEntry = enclosingControlStructures.rbegin(); 161 } else { 162 assert( false ); 163 } 164 165 if ( branchStmt->get_target() != "" && targetTable->find( branchStmt->get_target() ) == targetTable->end() ) { 163 166 throw SemanticError("The label defined in the exit loop statement does not exist: " + originalTarget ); // shouldn't happen (since that's already checked) 164 165 std::list< Entry >::iterator check; 166 if ( ( check = std::find( enclosingLoops.begin(), enclosingLoops.end(), (*targetTable)[branchStmt->get_target()] ) ) == enclosingLoops.end() ) 167 // not in loop, checking if in block 168 if ( (check = std::find( enclosingBlocks.begin(), enclosingBlocks.end(), (*targetTable)[branchStmt->get_target()] )) == enclosingBlocks.end() ) 169 // neither in loop nor in block, checking if in switch/choose 170 if ( (check = std::find( enclosingSwitches.begin(), enclosingSwitches.end(), (*targetTable)[branchStmt->get_target()] )) == enclosingSwitches.end() ) 171 throw SemanticError("The target specified in the exit loop statement does not correspond to an enclosing control structure: " + originalTarget ); 172 173 // what about exiting innermost block or switch??? 174 if ( enclosingLoops.back() == (*check) ) 175 return branchStmt; // exit the innermost loop (labels unnecessary) 167 } 176 168 177 169 // branch error checks, get the appropriate label name and create a goto … … 179 171 switch ( branchStmt->get_type() ) { 180 172 case BranchStmt::Break: 181 assert( check->useBreakExit() != "");182 exitLabel = check->useBreakExit();173 assert( targetEntry->useBreakExit() != ""); 174 exitLabel = targetEntry->useBreakExit(); 183 175 break; 184 176 case BranchStmt::Continue: 185 assert( check->useContExit() != "");186 exitLabel = check->useContExit();177 assert( targetEntry->useContExit() != ""); 178 exitLabel = targetEntry->useContExit(); 187 179 break; 188 180 default: … … 190 182 } // switch 191 183 192 return new BranchStmt( std::list<Label>(), exitLabel, BranchStmt::Goto ); 184 if ( branchStmt->get_target() == "" && branchStmt->get_type() != BranchStmt::Continue ) { 185 // unlabelled break/continue - can keep branch as break/continue for extra semantic information, but add 186 // exitLabel as its destination so that label passes can easily determine where the break/continue goes to 187 branchStmt->set_target( exitLabel ); 188 return branchStmt; 189 } else { 190 // labelled break/continue - can't easily emulate this with break and continue, so transform into a goto 191 delete branchStmt; 192 return new BranchStmt( std::list<Label>(), exitLabel, BranchStmt::Goto ); 193 } 193 194 } 194 195 … … 206 207 // continue label goes in the body as the last statement 207 208 std::list< Label > labels; labels.push_back( e.useContExit() ); 208 newBody->get_kids().push_back( new NullStmt( labels ) ); 209 newBody->get_kids().push_back( new NullStmt( labels ) ); 209 210 } 210 211 211 212 if ( e.isBreakUsed() ) { 212 // break label goes after the loop -- it'll get set by the 213 // break label goes after the loop -- it'll get set by the 213 214 // outer mutator if we do this 214 set_breakLabel( e.useBreakExit() ); 215 set_breakLabel( e.useBreakExit() ); 215 216 } 216 217 … … 231 232 232 233 Statement *MLEMutator::mutate( ChooseStmt *switchStmt ) { 233 return handleSwitchStmt( switchStmt ); 234 return handleSwitchStmt( switchStmt ); 234 235 } 235 236 -
src/ControlStruct/MLEMutator.h
r7305915 r87b5bf0 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // MLEMutator.h -- 7 // MLEMutator.h -- 8 8 // 9 9 // Author : Rodolfo G. Esteves … … 23 23 #include "SynTree/SynTree.h" 24 24 #include "SynTree/Mutator.h" 25 #include "SynTree/Label.h" 25 26 26 27 #include "LabelGenerator.h" … … 38 39 Statement *mutate( BranchStmt *branchStmt ) throw ( SemanticError ); 39 40 40 Statement *mutate( CaseStmt *caseStmt ); 41 Statement *mutate( CaseStmt *caseStmt ); 41 42 Statement *mutate( SwitchStmt *switchStmt ); 42 43 Statement *mutate( ChooseStmt *switchStmt ); … … 55 56 bool operator!=( const Statement *stmt ) { return ( loop != stmt ); } 56 57 57 bool operator==( const Entry &other ) { return ( loop == other.get_ loop() ); }58 bool operator==( const Entry &other ) { return ( loop == other.get_controlStructure() ); } 58 59 59 Statement *get_ loop() const { return loop; }60 Statement *get_controlStructure() const { return loop; } 60 61 61 62 Label useContExit() { contUsed = true; return contExit; } … … 72 73 73 74 std::map< Label, Statement * > *targetTable; 74 std::list< Entry > enclosing Blocks, enclosingLoops, enclosingSwitches;75 std::list< Entry > enclosingControlStructures; 75 76 Label breakLabel; 76 77 LabelGenerator *generator; … … 79 80 Statement *handleLoopStmt( LoopClass *loopStmt ); 80 81 81 template< typename SwitchClass > 82 template< typename SwitchClass > 82 83 Statement *handleSwitchStmt( SwitchClass *switchStmt ); 83 84 -
src/ControlStruct/Mutate.cc
r7305915 r87b5bf0 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // Mutate.cc -- 7 // Mutate.cc -- 8 8 // 9 9 // Author : Rodolfo G. Esteves … … 39 39 ForExprMutator formut; 40 40 41 // transform choose statements into switch statements 42 ChooseMutator chmut; 43 41 44 // normalizes label definitions and generates multi-level 42 45 // exit labels 43 46 LabelFixer lfix; 44 45 // transform choose statements into switch statements46 ChooseMutator chmut;47 47 48 48 // expand case ranges and turn fallthru into a null statement … … 53 53 54 54 mutateAll( translationUnit, formut ); 55 mutateAll( translationUnit, chmut ); 55 56 acceptAll( translationUnit, lfix ); 56 mutateAll( translationUnit, chmut );57 57 mutateAll( translationUnit, ranges ); 58 58 //mutateAll( translationUnit, exc ); -
src/GenPoly/Specialize.cc
r7305915 r87b5bf0 99 99 } // if 100 100 // create new thunk with same signature as formal type (C linkage, empty body) 101 FunctionDecl *thunkFunc = new FunctionDecl( thunkNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, newType, new CompoundStmt( std::list< std::string >()), false, false );101 FunctionDecl *thunkFunc = new FunctionDecl( thunkNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, newType, new CompoundStmt( noLabels ), false, false ); 102 102 thunkFunc->fixUniqueId(); 103 103 -
src/InitTweak/FixInit.cc
r7305915 r87b5bf0 16 16 #include <stack> 17 17 #include <list> 18 #include <iterator> 19 #include <algorithm> 18 20 #include "FixInit.h" 19 21 #include "InitTweak.h" … … 28 30 #include "SymTab/Indexer.h" 29 31 #include "GenPoly/PolyMutator.h" 32 #include "SynTree/AddStmtVisitor.h" 30 33 31 34 bool ctordtorp = false; 35 bool ctorp = false; 36 bool cpctorp = false; 37 bool dtorp = false; 32 38 #define PRINT( text ) if ( ctordtorp ) { text } 39 #define CP_CTOR_PRINT( text ) if ( ctordtorp || cpctorp ) { text } 40 #define DTOR_PRINT( text ) if ( ctordtorp || dtorp ) { text } 33 41 34 42 namespace InitTweak { … … 36 44 const std::list<Label> noLabels; 37 45 const std::list<Expression*> noDesignators; 38 } 39 40 class InsertImplicitCalls : public GenPoly::PolyMutator { 41 public: 42 /// wrap function application expressions as ImplicitCopyCtorExpr nodes 43 /// so that it is easy to identify which function calls need their parameters 44 /// to be copy constructed 45 static void insert( std::list< Declaration * > & translationUnit ); 46 47 virtual Expression * mutate( ApplicationExpr * appExpr ); 48 }; 49 50 class ResolveCopyCtors : public SymTab::Indexer { 51 public: 52 /// generate temporary ObjectDecls for each argument and return value of each 53 /// ImplicitCopyCtorExpr, generate/resolve copy construction expressions for each, 54 /// and generate/resolve destructors for both arguments and return value temporaries 55 static void resolveImplicitCalls( std::list< Declaration * > & translationUnit ); 56 57 virtual void visit( ImplicitCopyCtorExpr * impCpCtorExpr ); 58 59 /// create and resolve ctor/dtor expression: fname(var, [cpArg]) 60 ApplicationExpr * makeCtorDtor( const std::string & fname, ObjectDecl * var, Expression * cpArg = NULL ); 61 /// true if type does not need to be copy constructed to ensure correctness 62 bool skipCopyConstruct( Type * ); 63 private: 64 TypeSubstitution * env; 65 }; 66 67 class FixInit : public GenPoly::PolyMutator { 68 public: 69 /// expand each object declaration to use its constructor after it is declared. 70 /// insert destructor calls at the appropriate places 71 static void fixInitializers( std::list< Declaration * > &translationUnit ); 72 73 virtual DeclarationWithType * mutate( ObjectDecl *objDecl ); 74 75 virtual CompoundStmt * mutate( CompoundStmt * compoundStmt ); 76 virtual Statement * mutate( ReturnStmt * returnStmt ); 77 virtual Statement * mutate( BranchStmt * branchStmt ); 78 79 private: 80 // stack of list of statements - used to differentiate scopes 81 std::list< std::list< Statement * > > dtorStmts; 82 }; 83 84 class FixCopyCtors : public GenPoly::PolyMutator { 85 public: 86 /// expand ImplicitCopyCtorExpr nodes into the temporary declarations, copy constructors, 87 /// call expression, and destructors 88 static void fixCopyCtors( std::list< Declaration * > &translationUnit ); 89 90 virtual Expression * mutate( ImplicitCopyCtorExpr * impCpCtorExpr ); 91 92 private: 93 // stack of list of statements - used to differentiate scopes 94 std::list< std::list< Statement * > > dtorStmts; 95 }; 46 47 class InsertImplicitCalls : public GenPoly::PolyMutator { 48 public: 49 /// wrap function application expressions as ImplicitCopyCtorExpr nodes 50 /// so that it is easy to identify which function calls need their parameters 51 /// to be copy constructed 52 static void insert( std::list< Declaration * > & translationUnit ); 53 54 virtual Expression * mutate( ApplicationExpr * appExpr ); 55 }; 56 57 class ResolveCopyCtors : public SymTab::Indexer { 58 public: 59 /// generate temporary ObjectDecls for each argument and return value of each 60 /// ImplicitCopyCtorExpr, generate/resolve copy construction expressions for each, 61 /// and generate/resolve destructors for both arguments and return value temporaries 62 static void resolveImplicitCalls( std::list< Declaration * > & translationUnit ); 63 64 virtual void visit( ImplicitCopyCtorExpr * impCpCtorExpr ); 65 66 /// create and resolve ctor/dtor expression: fname(var, [cpArg]) 67 ApplicationExpr * makeCtorDtor( const std::string & fname, ObjectDecl * var, Expression * cpArg = NULL ); 68 /// true if type does not need to be copy constructed to ensure correctness 69 bool skipCopyConstruct( Type * ); 70 private: 71 TypeSubstitution * env; 72 }; 73 74 /// collects constructed object decls - used as a base class 75 class ObjDeclCollector : public AddStmtVisitor { 76 public: 77 typedef AddStmtVisitor Parent; 78 using Parent::visit; 79 typedef std::set< ObjectDecl * > ObjectSet; 80 virtual void visit( CompoundStmt *compoundStmt ); 81 virtual void visit( DeclStmt *stmt ); 82 protected: 83 ObjectSet curVars; 84 }; 85 86 struct printSet { 87 typedef ObjDeclCollector::ObjectSet ObjectSet; 88 printSet( const ObjectSet & objs ) : objs( objs ) {} 89 const ObjectSet & objs; 90 }; 91 std::ostream & operator<<( std::ostream & out, const printSet & set) { 92 out << "{ "; 93 for ( ObjectDecl * obj : set.objs ) { 94 out << obj->get_name() << ", " ; 95 } 96 out << " }"; 97 return out; 98 } 99 100 class LabelFinder : public ObjDeclCollector { 101 public: 102 typedef ObjDeclCollector Parent; 103 typedef std::map< Label, ObjectSet > LabelMap; 104 // map of Label -> live variables at that label 105 LabelMap vars; 106 107 void handleStmt( Statement * stmt ); 108 109 // xxx - This needs to be done better. 110 // allow some generalization among different kinds of nodes with 111 // with similar parentage (e.g. all expressions, all statements, etc.) 112 // important to have this to provide a single entry point so that as 113 // new subclasses are added, there is only one place that the code has 114 // to be updated, rather than ensure that every specialized class knows 115 // about every new kind of statement that might be added. 116 virtual void visit( CompoundStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 117 virtual void visit( ExprStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 118 virtual void visit( AsmStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 119 virtual void visit( IfStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 120 virtual void visit( WhileStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 121 virtual void visit( ForStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 122 virtual void visit( SwitchStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 123 virtual void visit( ChooseStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 124 virtual void visit( FallthruStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 125 virtual void visit( CaseStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 126 virtual void visit( BranchStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 127 virtual void visit( ReturnStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 128 virtual void visit( TryStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 129 virtual void visit( CatchStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 130 virtual void visit( FinallyStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 131 virtual void visit( NullStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 132 virtual void visit( DeclStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 133 virtual void visit( ImplicitCtorDtorStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 134 }; 135 136 class InsertDtors : public ObjDeclCollector { 137 public: 138 /// insert destructor calls at the appropriate places. 139 /// must happen before CtorInit nodes are removed (currently by FixInit) 140 static void insert( std::list< Declaration * > & translationUnit ); 141 142 typedef ObjDeclCollector Parent; 143 typedef std::list< ObjectDecl * > OrderedDecls; 144 typedef std::list< OrderedDecls > OrderedDeclsStack; 145 146 InsertDtors( LabelFinder & finder ) : labelVars( finder.vars ) {} 147 148 virtual void visit( ObjectDecl * objDecl ); 149 150 virtual void visit( CompoundStmt * compoundStmt ); 151 virtual void visit( ReturnStmt * returnStmt ); 152 virtual void visit( BranchStmt * stmt ); 153 private: 154 void handleGoto( BranchStmt * stmt ); 155 156 LabelFinder::LabelMap & labelVars; 157 OrderedDeclsStack reverseDeclOrder; 158 }; 159 160 class FixInit : public GenPoly::PolyMutator { 161 public: 162 /// expand each object declaration to use its constructor after it is declared. 163 static void fixInitializers( std::list< Declaration * > &translationUnit ); 164 165 virtual DeclarationWithType * mutate( ObjectDecl *objDecl ); 166 }; 167 168 class FixCopyCtors : public GenPoly::PolyMutator { 169 public: 170 /// expand ImplicitCopyCtorExpr nodes into the temporary declarations, copy constructors, 171 /// call expression, and destructors 172 static void fixCopyCtors( std::list< Declaration * > &translationUnit ); 173 174 virtual Expression * mutate( ImplicitCopyCtorExpr * impCpCtorExpr ); 175 }; 176 } // namespace 96 177 97 178 void fix( std::list< Declaration * > & translationUnit ) { 98 179 InsertImplicitCalls::insert( translationUnit ); 99 180 ResolveCopyCtors::resolveImplicitCalls( translationUnit ); 181 InsertDtors::insert( translationUnit ); 100 182 FixInit::fixInitializers( translationUnit ); 183 101 184 // FixCopyCtors must happen after FixInit, so that destructors are placed correctly 102 185 FixCopyCtors::fixCopyCtors( translationUnit ); 103 186 } 104 187 105 void InsertImplicitCalls::insert( std::list< Declaration * > & translationUnit ) { 106 InsertImplicitCalls inserter; 107 mutateAll( translationUnit, inserter ); 108 } 109 110 void ResolveCopyCtors::resolveImplicitCalls( std::list< Declaration * > & translationUnit ) { 111 ResolveCopyCtors resolver; 112 acceptAll( translationUnit, resolver ); 113 } 114 115 void FixInit::fixInitializers( std::list< Declaration * > & translationUnit ) { 116 FixInit fixer; 117 mutateAll( translationUnit, fixer ); 118 } 119 120 void FixCopyCtors::fixCopyCtors( std::list< Declaration * > & translationUnit ) { 121 FixCopyCtors fixer; 122 mutateAll( translationUnit, fixer ); 123 } 124 125 Expression * InsertImplicitCalls::mutate( ApplicationExpr * appExpr ) { 126 appExpr = dynamic_cast< ApplicationExpr * >( Mutator::mutate( appExpr ) ); 127 assert( appExpr ); 128 129 if ( VariableExpr * function = dynamic_cast< VariableExpr * > ( appExpr->get_function() ) ) { 130 if ( function->get_var()->get_linkage() == LinkageSpec::Intrinsic ) { 131 // optimization: don't need to copy construct in order to call intrinsic functions 132 return appExpr; 133 } else if ( DeclarationWithType * funcDecl = dynamic_cast< DeclarationWithType * > ( function->get_var() ) ) { 134 FunctionType * ftype = dynamic_cast< FunctionType * >( GenPoly::getFunctionType( funcDecl->get_type() ) ); 135 assert( ftype ); 136 if ( (funcDecl->get_name() == "?{}" || funcDecl->get_name() == "?=?") && ftype->get_parameters().size() == 2 ) { 137 Type * t1 = ftype->get_parameters().front()->get_type(); 138 Type * t2 = ftype->get_parameters().back()->get_type(); 139 PointerType * ptrType = dynamic_cast< PointerType * > ( t1 ); 140 assert( ptrType ); 141 142 if ( ResolvExpr::typesCompatible( ptrType->get_base(), t2, SymTab::Indexer() ) ) { 143 // optimization: don't need to copy construct in order to call a copy constructor or 144 // assignment operator 188 namespace { 189 void InsertImplicitCalls::insert( std::list< Declaration * > & translationUnit ) { 190 InsertImplicitCalls inserter; 191 mutateAll( translationUnit, inserter ); 192 } 193 194 void ResolveCopyCtors::resolveImplicitCalls( std::list< Declaration * > & translationUnit ) { 195 ResolveCopyCtors resolver; 196 acceptAll( translationUnit, resolver ); 197 } 198 199 void FixInit::fixInitializers( std::list< Declaration * > & translationUnit ) { 200 FixInit fixer; 201 mutateAll( translationUnit, fixer ); 202 } 203 204 void InsertDtors::insert( std::list< Declaration * > & translationUnit ) { 205 LabelFinder finder; 206 InsertDtors inserter( finder ); 207 acceptAll( translationUnit, finder ); 208 acceptAll( translationUnit, inserter ); 209 } 210 211 void FixCopyCtors::fixCopyCtors( std::list< Declaration * > & translationUnit ) { 212 FixCopyCtors fixer; 213 mutateAll( translationUnit, fixer ); 214 } 215 216 Expression * InsertImplicitCalls::mutate( ApplicationExpr * appExpr ) { 217 appExpr = dynamic_cast< ApplicationExpr * >( Mutator::mutate( appExpr ) ); 218 assert( appExpr ); 219 220 if ( VariableExpr * function = dynamic_cast< VariableExpr * > ( appExpr->get_function() ) ) { 221 if ( function->get_var()->get_linkage() == LinkageSpec::Intrinsic ) { 222 // optimization: don't need to copy construct in order to call intrinsic functions 223 return appExpr; 224 } else if ( DeclarationWithType * funcDecl = dynamic_cast< DeclarationWithType * > ( function->get_var() ) ) { 225 FunctionType * ftype = dynamic_cast< FunctionType * >( GenPoly::getFunctionType( funcDecl->get_type() ) ); 226 assert( ftype ); 227 if ( (funcDecl->get_name() == "?{}" || funcDecl->get_name() == "?=?") && ftype->get_parameters().size() == 2 ) { 228 Type * t1 = ftype->get_parameters().front()->get_type(); 229 Type * t2 = ftype->get_parameters().back()->get_type(); 230 PointerType * ptrType = dynamic_cast< PointerType * > ( t1 ); 231 assert( ptrType ); 232 233 if ( ResolvExpr::typesCompatible( ptrType->get_base(), t2, SymTab::Indexer() ) ) { 234 // optimization: don't need to copy construct in order to call a copy constructor or 235 // assignment operator 236 return appExpr; 237 } 238 } else if ( funcDecl->get_name() == "^?{}" ) { 239 // correctness: never copy construct arguments to a destructor 145 240 return appExpr; 146 241 } 147 } else if ( funcDecl->get_name() == "^?{}" ) {148 // correctness: never copy construct arguments to a destructor149 return appExpr;150 242 } 151 243 } 152 } 153 PRINT( std::cerr << "InsertImplicitCalls: adding a wrapper " << appExpr << std::endl; ) 154 155 // wrap each function call so that it is easy to identify nodes that have to be copy constructed 156 ImplicitCopyCtorExpr * expr = new ImplicitCopyCtorExpr( appExpr ); 157 // save the type substitution onto the new node so that it is easy to find. 158 // Ensure it is not deleted with the ImplicitCopyCtorExpr by removing it before deletion. 159 // The substitution is needed to obtain the type of temporary variables so that copy constructor 160 // calls can be resolved. Normally this is what PolyMutator is for, but the pass that resolves 161 // copy constructor calls must be an Indexer. We could alternatively make a PolyIndexer which 162 // saves the environment, or compute the types of temporaries here, but it's much simpler to 163 // save the environment here, and more cohesive to compute temporary variables and resolve copy 164 // constructor calls together. 165 assert( env ); 166 expr->set_env( env ); 167 return expr; 168 } 169 170 bool ResolveCopyCtors::skipCopyConstruct( Type * type ) { 171 return dynamic_cast< VarArgsType * >( type ) || GenPoly::getFunctionType( type ); 172 } 173 174 ApplicationExpr * ResolveCopyCtors::makeCtorDtor( const std::string & fname, ObjectDecl * var, Expression * cpArg ) { 175 assert( var ); 176 UntypedExpr * untyped = new UntypedExpr( new NameExpr( fname ) ); 177 untyped->get_args().push_back( new AddressExpr( new VariableExpr( var ) ) ); 178 if (cpArg) untyped->get_args().push_back( cpArg ); 179 180 // resolve copy constructor 181 // should only be one alternative for copy ctor and dtor expressions, since 182 // all arguments are fixed (VariableExpr and already resolved expression) 183 PRINT( std::cerr << "ResolvingCtorDtor " << untyped << std::endl; ) 184 ApplicationExpr * resolved = dynamic_cast< ApplicationExpr * >( ResolvExpr::findVoidExpression( untyped, *this ) ); 185 if ( resolved->get_env() ) { 186 env->add( *resolved->get_env() ); 187 } 188 189 assert( resolved ); 190 delete untyped; 191 return resolved; 192 } 193 194 void ResolveCopyCtors::visit( ImplicitCopyCtorExpr *impCpCtorExpr ) { 195 static UniqueName tempNamer("_tmp_cp"); 196 static UniqueName retNamer("_tmp_cp_ret"); 197 198 PRINT( std::cerr << "ResolveCopyCtors: " << impCpCtorExpr << std::endl; ) 199 Visitor::visit( impCpCtorExpr ); 200 env = impCpCtorExpr->get_env(); // xxx - maybe we really should just have a PolyIndexer... 201 202 ApplicationExpr * appExpr = impCpCtorExpr->get_callExpr(); 203 204 // take each argument and attempt to copy construct it. 205 for ( Expression * & arg : appExpr->get_args() ) { 206 PRINT( std::cerr << "Type Substitution: " << *impCpCtorExpr->get_env() << std::endl; ) 207 // xxx - need to handle tuple arguments 208 assert( ! arg->get_results().empty() ); 209 Type * result = arg->get_results().front(); 210 if ( skipCopyConstruct( result ) ) continue; // skip certain non-copyable types 211 // type may involve type variables, so apply type substitution to get temporary variable's actual type 212 result = result->clone(); 213 impCpCtorExpr->get_env()->apply( result ); 214 ObjectDecl * tmp = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, result, 0 ); 215 tmp->get_type()->set_isConst( false ); 216 217 // create and resolve copy constructor 218 PRINT( std::cerr << "makeCtorDtor for an argument" << std::endl; ) 219 ApplicationExpr * cpCtor = makeCtorDtor( "?{}", tmp, arg ); 220 221 // if the chosen constructor is intrinsic, the copy is unnecessary, so 222 // don't create the temporary and don't call the copy constructor 223 VariableExpr * function = dynamic_cast< VariableExpr * >( cpCtor->get_function() ); 224 assert( function ); 225 if ( function->get_var()->get_linkage() != LinkageSpec::Intrinsic ) { 226 // replace argument to function call with temporary 227 arg = new CommaExpr( cpCtor, new VariableExpr( tmp ) ); 228 impCpCtorExpr->get_tempDecls().push_back( tmp ); 229 impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", tmp ) ); 230 } 231 } 232 233 // each return value from the call needs to be connected with an ObjectDecl 234 // at the call site, which is initialized with the return value and is destructed 235 // later 236 // xxx - handle multiple return values 237 ApplicationExpr * callExpr = impCpCtorExpr->get_callExpr(); 238 // xxx - is this right? callExpr may not have the right environment, because it was attached 239 // at a higher level. Trying to pass that environment along. 240 callExpr->set_env( impCpCtorExpr->get_env()->clone() ); 241 for ( Type * result : appExpr->get_results() ) { 242 result = result->clone(); 243 impCpCtorExpr->get_env()->apply( result ); 244 ObjectDecl * ret = new ObjectDecl( retNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, result, 0 ); 245 ret->get_type()->set_isConst( false ); 246 impCpCtorExpr->get_returnDecls().push_back( ret ); 247 PRINT( std::cerr << "makeCtorDtor for a return" << std::endl; ) 248 impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) ); 249 } 250 PRINT( std::cerr << "after Resolving: " << impCpCtorExpr << std::endl; ) 251 } 252 253 254 Expression * FixCopyCtors::mutate( ImplicitCopyCtorExpr * impCpCtorExpr ) { 255 PRINT( std::cerr << "FixCopyCtors: " << impCpCtorExpr << std::endl; ) 256 257 impCpCtorExpr = dynamic_cast< ImplicitCopyCtorExpr * >( Mutator::mutate( impCpCtorExpr ) ); 258 assert( impCpCtorExpr ); 259 260 std::list< ObjectDecl * > & tempDecls = impCpCtorExpr->get_tempDecls(); 261 std::list< ObjectDecl * > & returnDecls = impCpCtorExpr->get_returnDecls(); 262 std::list< Expression * > & dtors = impCpCtorExpr->get_dtors(); 263 264 // add all temporary declarations and their constructors 265 for ( ObjectDecl * obj : tempDecls ) { 266 stmtsToAdd.push_back( new DeclStmt( noLabels, obj ) ); 267 } 268 for ( ObjectDecl * obj : returnDecls ) { 269 stmtsToAdd.push_back( new DeclStmt( noLabels, obj ) ); 270 } 271 272 // add destructors after current statement 273 for ( Expression * dtor : dtors ) { 274 stmtsToAddAfter.push_back( new ExprStmt( noLabels, dtor ) ); 275 } 276 277 // xxx - update to work with multiple return values 278 ObjectDecl * returnDecl = returnDecls.empty() ? NULL : returnDecls.front(); 279 Expression * callExpr = impCpCtorExpr->get_callExpr(); 280 281 PRINT( std::cerr << "Coming out the back..." << impCpCtorExpr << std::endl; ) 282 283 // xxx - some of these aren't necessary, and can be removed once this is stable 284 dtors.clear(); 285 tempDecls.clear(); 286 returnDecls.clear(); 287 impCpCtorExpr->set_callExpr( NULL ); 288 impCpCtorExpr->set_env( NULL ); 289 delete impCpCtorExpr; 290 291 if ( returnDecl ) { 292 UntypedExpr * assign = new UntypedExpr( new NameExpr( "?=?" ) ); 293 assign->get_args().push_back( new VariableExpr( returnDecl ) ); 294 assign->get_args().push_back( callExpr ); 295 // know the result type of the assignment is the type of the LHS (minus the pointer), so 296 // add that onto the assignment expression so that later steps have the necessary information 297 assign->add_result( returnDecl->get_type()->clone() ); 298 299 Expression * retExpr = new CommaExpr( assign, new VariableExpr( returnDecl ) ); 300 if ( callExpr->get_results().front()->get_isLvalue() ) { 301 // lvalue returning functions are funny. Lvalue.cc inserts a *? in front of any 302 // lvalue returning non-intrinsic function. Add an AddressExpr to the call to negate 303 // the derefence and change the type of the return temporary from T to T* to properly 304 // capture the return value. Then dereference the result of the comma expression, since 305 // the lvalue returning call was originally wrapped with an AddressExpr. 306 // Effectively, this turns 307 // lvalue T f(); 308 // &*f() 309 // into 310 // T * tmp_cp_retN; 311 // tmp_cp_ret_N = &*(tmp_cp_ret_N = &*f(), tmp_cp_ret); 312 // which work out in terms of types, but is pretty messy. It would be nice to find a better way. 313 assign->get_args().back() = new AddressExpr( assign->get_args().back() ); 314 315 Type * resultType = returnDecl->get_type()->clone(); 316 returnDecl->set_type( new PointerType( Type::Qualifiers(), returnDecl->get_type() ) ); 317 UntypedExpr * deref = new UntypedExpr( new NameExpr( "*?" ) ); 318 deref->get_args().push_back( retExpr ); 319 deref->add_result( resultType ); 320 retExpr = deref; 321 } 322 // xxx - might need to set env on retExpr... 323 // retExpr->set_env( env->clone() ); 324 return retExpr; 325 } else { 326 return callExpr; 327 } 328 } 329 330 DeclarationWithType *FixInit::mutate( ObjectDecl *objDecl ) { 331 // first recursively handle pieces of ObjectDecl so that they aren't missed by other visitors 332 // when the init is removed from the ObjectDecl 333 objDecl = dynamic_cast< ObjectDecl * >( Mutator::mutate( objDecl ) ); 334 335 if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) { 336 // a decision should have been made by the resolver, so ctor and init are not both non-NULL 337 assert( ! ctorInit->get_ctor() || ! ctorInit->get_init() ); 338 if ( Statement * ctor = ctorInit->get_ctor() ) { 339 if ( objDecl->get_storageClass() == DeclarationNode::Static ) { 340 // generate: 341 // static bool __objName_uninitialized = true; 342 // if (__objName_uninitialized) { 343 // __ctor(__objName); 344 // void dtor_atexit() { 345 // __dtor(__objName); 346 // } 347 // on_exit(dtorOnExit, &__objName); 348 // __objName_uninitialized = false; 349 // } 350 351 // generate first line 352 BasicType * boolType = new BasicType( Type::Qualifiers(), BasicType::Bool ); 353 SingleInit * boolInitExpr = new SingleInit( new ConstantExpr( Constant( boolType->clone(), "1" ) ), noDesignators ); 354 ObjectDecl * isUninitializedVar = new ObjectDecl( objDecl->get_mangleName() + "_uninitialized", DeclarationNode::Static, LinkageSpec::Cforall, 0, boolType, boolInitExpr ); 355 isUninitializedVar->fixUniqueId(); 356 357 // void dtor_atexit(...) {...} 358 FunctionDecl * dtorCaller = new FunctionDecl( objDecl->get_mangleName() + "_dtor_atexit", DeclarationNode::NoStorageClass, LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt( noLabels ), false, false ); 359 dtorCaller->fixUniqueId(); 360 dtorCaller->get_statements()->get_kids().push_back( ctorInit->get_dtor() ); 361 362 // on_exit(dtor_atexit); 363 UntypedExpr * callAtexit = new UntypedExpr( new NameExpr( "atexit" ) ); 364 callAtexit->get_args().push_back( new VariableExpr( dtorCaller ) ); 365 366 // __objName_uninitialized = false; 367 UntypedExpr * setTrue = new UntypedExpr( new NameExpr( "?=?" ) ); 368 setTrue->get_args().push_back( new VariableExpr( isUninitializedVar ) ); 369 setTrue->get_args().push_back( new ConstantExpr( Constant( boolType->clone(), "0" ) ) ); 370 371 // generate body of if 372 CompoundStmt * initStmts = new CompoundStmt( noLabels ); 373 std::list< Statement * > & body = initStmts->get_kids(); 374 body.push_back( ctor ); 375 body.push_back( new DeclStmt( noLabels, dtorCaller ) ); 376 body.push_back( new ExprStmt( noLabels, callAtexit ) ); 377 body.push_back( new ExprStmt( noLabels, setTrue ) ); 378 379 // put it all together 380 IfStmt * ifStmt = new IfStmt( noLabels, new VariableExpr( isUninitializedVar ), initStmts, 0 ); 381 stmtsToAddAfter.push_back( new DeclStmt( noLabels, isUninitializedVar ) ); 382 stmtsToAddAfter.push_back( ifStmt ); 244 CP_CTOR_PRINT( std::cerr << "InsertImplicitCalls: adding a wrapper " << appExpr << std::endl; ) 245 246 // wrap each function call so that it is easy to identify nodes that have to be copy constructed 247 ImplicitCopyCtorExpr * expr = new ImplicitCopyCtorExpr( appExpr ); 248 // save the type substitution onto the new node so that it is easy to find. 249 // Ensure it is not deleted with the ImplicitCopyCtorExpr by removing it before deletion. 250 // The substitution is needed to obtain the type of temporary variables so that copy constructor 251 // calls can be resolved. Normally this is what PolyMutator is for, but the pass that resolves 252 // copy constructor calls must be an Indexer. We could alternatively make a PolyIndexer which 253 // saves the environment, or compute the types of temporaries here, but it's much simpler to 254 // save the environment here, and more cohesive to compute temporary variables and resolve copy 255 // constructor calls together. 256 assert( env ); 257 expr->set_env( env ); 258 return expr; 259 } 260 261 bool ResolveCopyCtors::skipCopyConstruct( Type * type ) { 262 return dynamic_cast< VarArgsType * >( type ) || GenPoly::getFunctionType( type ); 263 } 264 265 ApplicationExpr * ResolveCopyCtors::makeCtorDtor( const std::string & fname, ObjectDecl * var, Expression * cpArg ) { 266 assert( var ); 267 UntypedExpr * untyped = new UntypedExpr( new NameExpr( fname ) ); 268 untyped->get_args().push_back( new AddressExpr( new VariableExpr( var ) ) ); 269 if (cpArg) untyped->get_args().push_back( cpArg ); 270 271 // resolve copy constructor 272 // should only be one alternative for copy ctor and dtor expressions, since 273 // all arguments are fixed (VariableExpr and already resolved expression) 274 CP_CTOR_PRINT( std::cerr << "ResolvingCtorDtor " << untyped << std::endl; ) 275 ApplicationExpr * resolved = dynamic_cast< ApplicationExpr * >( ResolvExpr::findVoidExpression( untyped, *this ) ); 276 if ( resolved->get_env() ) { 277 env->add( *resolved->get_env() ); 278 } 279 280 assert( resolved ); 281 delete untyped; 282 return resolved; 283 } 284 285 void ResolveCopyCtors::visit( ImplicitCopyCtorExpr *impCpCtorExpr ) { 286 static UniqueName tempNamer("_tmp_cp"); 287 static UniqueName retNamer("_tmp_cp_ret"); 288 289 CP_CTOR_PRINT( std::cerr << "ResolveCopyCtors: " << impCpCtorExpr << std::endl; ) 290 Visitor::visit( impCpCtorExpr ); 291 env = impCpCtorExpr->get_env(); // xxx - maybe we really should just have a PolyIndexer... 292 293 ApplicationExpr * appExpr = impCpCtorExpr->get_callExpr(); 294 295 // take each argument and attempt to copy construct it. 296 for ( Expression * & arg : appExpr->get_args() ) { 297 CP_CTOR_PRINT( std::cerr << "Type Substitution: " << *impCpCtorExpr->get_env() << std::endl; ) 298 // xxx - need to handle tuple arguments 299 assert( ! arg->get_results().empty() ); 300 Type * result = arg->get_results().front(); 301 if ( skipCopyConstruct( result ) ) continue; // skip certain non-copyable types 302 // type may involve type variables, so apply type substitution to get temporary variable's actual type 303 result = result->clone(); 304 impCpCtorExpr->get_env()->apply( result ); 305 ObjectDecl * tmp = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, result, 0 ); 306 tmp->get_type()->set_isConst( false ); 307 308 // create and resolve copy constructor 309 CP_CTOR_PRINT( std::cerr << "makeCtorDtor for an argument" << std::endl; ) 310 ApplicationExpr * cpCtor = makeCtorDtor( "?{}", tmp, arg ); 311 312 // if the chosen constructor is intrinsic, the copy is unnecessary, so 313 // don't create the temporary and don't call the copy constructor 314 VariableExpr * function = dynamic_cast< VariableExpr * >( cpCtor->get_function() ); 315 assert( function ); 316 if ( function->get_var()->get_linkage() != LinkageSpec::Intrinsic ) { 317 // replace argument to function call with temporary 318 arg = new CommaExpr( cpCtor, new VariableExpr( tmp ) ); 319 impCpCtorExpr->get_tempDecls().push_back( tmp ); 320 impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", tmp ) ); 321 } 322 } 323 324 // each return value from the call needs to be connected with an ObjectDecl 325 // at the call site, which is initialized with the return value and is destructed 326 // later 327 // xxx - handle multiple return values 328 ApplicationExpr * callExpr = impCpCtorExpr->get_callExpr(); 329 // xxx - is this right? callExpr may not have the right environment, because it was attached 330 // at a higher level. Trying to pass that environment along. 331 callExpr->set_env( impCpCtorExpr->get_env()->clone() ); 332 for ( Type * result : appExpr->get_results() ) { 333 result = result->clone(); 334 impCpCtorExpr->get_env()->apply( result ); 335 ObjectDecl * ret = new ObjectDecl( retNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, result, 0 ); 336 ret->get_type()->set_isConst( false ); 337 impCpCtorExpr->get_returnDecls().push_back( ret ); 338 CP_CTOR_PRINT( std::cerr << "makeCtorDtor for a return" << std::endl; ) 339 impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) ); 340 } 341 CP_CTOR_PRINT( std::cerr << "after Resolving: " << impCpCtorExpr << std::endl; ) 342 } 343 344 345 Expression * FixCopyCtors::mutate( ImplicitCopyCtorExpr * impCpCtorExpr ) { 346 CP_CTOR_PRINT( std::cerr << "FixCopyCtors: " << impCpCtorExpr << std::endl; ) 347 348 impCpCtorExpr = dynamic_cast< ImplicitCopyCtorExpr * >( Mutator::mutate( impCpCtorExpr ) ); 349 assert( impCpCtorExpr ); 350 351 std::list< ObjectDecl * > & tempDecls = impCpCtorExpr->get_tempDecls(); 352 std::list< ObjectDecl * > & returnDecls = impCpCtorExpr->get_returnDecls(); 353 std::list< Expression * > & dtors = impCpCtorExpr->get_dtors(); 354 355 // add all temporary declarations and their constructors 356 for ( ObjectDecl * obj : tempDecls ) { 357 stmtsToAdd.push_back( new DeclStmt( noLabels, obj ) ); 358 } 359 for ( ObjectDecl * obj : returnDecls ) { 360 stmtsToAdd.push_back( new DeclStmt( noLabels, obj ) ); 361 } 362 363 // add destructors after current statement 364 for ( Expression * dtor : dtors ) { 365 stmtsToAddAfter.push_back( new ExprStmt( noLabels, dtor ) ); 366 } 367 368 // xxx - update to work with multiple return values 369 ObjectDecl * returnDecl = returnDecls.empty() ? NULL : returnDecls.front(); 370 Expression * callExpr = impCpCtorExpr->get_callExpr(); 371 372 CP_CTOR_PRINT( std::cerr << "Coming out the back..." << impCpCtorExpr << std::endl; ) 373 374 // detach fields from wrapper node so that it can be deleted without deleting too much 375 dtors.clear(); 376 tempDecls.clear(); 377 returnDecls.clear(); 378 impCpCtorExpr->set_callExpr( NULL ); 379 impCpCtorExpr->set_env( NULL ); 380 delete impCpCtorExpr; 381 382 if ( returnDecl ) { 383 UntypedExpr * assign = new UntypedExpr( new NameExpr( "?=?" ) ); 384 assign->get_args().push_back( new VariableExpr( returnDecl ) ); 385 assign->get_args().push_back( callExpr ); 386 // know the result type of the assignment is the type of the LHS (minus the pointer), so 387 // add that onto the assignment expression so that later steps have the necessary information 388 assign->add_result( returnDecl->get_type()->clone() ); 389 390 Expression * retExpr = new CommaExpr( assign, new VariableExpr( returnDecl ) ); 391 if ( callExpr->get_results().front()->get_isLvalue() ) { 392 // lvalue returning functions are funny. Lvalue.cc inserts a *? in front of any 393 // lvalue returning non-intrinsic function. Add an AddressExpr to the call to negate 394 // the derefence and change the type of the return temporary from T to T* to properly 395 // capture the return value. Then dereference the result of the comma expression, since 396 // the lvalue returning call was originally wrapped with an AddressExpr. 397 // Effectively, this turns 398 // lvalue T f(); 399 // &*f() 400 // into 401 // T * tmp_cp_retN; 402 // tmp_cp_ret_N = &*(tmp_cp_ret_N = &*f(), tmp_cp_ret); 403 // which work out in terms of types, but is pretty messy. It would be nice to find a better way. 404 assign->get_args().back() = new AddressExpr( assign->get_args().back() ); 405 406 Type * resultType = returnDecl->get_type()->clone(); 407 returnDecl->set_type( new PointerType( Type::Qualifiers(), returnDecl->get_type() ) ); 408 UntypedExpr * deref = new UntypedExpr( new NameExpr( "*?" ) ); 409 deref->get_args().push_back( retExpr ); 410 deref->add_result( resultType ); 411 retExpr = deref; 412 } 413 // xxx - might need to set env on retExpr... 414 // retExpr->set_env( env->clone() ); 415 return retExpr; 416 } else { 417 return callExpr; 418 } 419 } 420 421 DeclarationWithType *FixInit::mutate( ObjectDecl *objDecl ) { 422 // first recursively handle pieces of ObjectDecl so that they aren't missed by other visitors 423 // when the init is removed from the ObjectDecl 424 objDecl = dynamic_cast< ObjectDecl * >( Mutator::mutate( objDecl ) ); 425 426 if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) { 427 // a decision should have been made by the resolver, so ctor and init are not both non-NULL 428 assert( ! ctorInit->get_ctor() || ! ctorInit->get_init() ); 429 if ( Statement * ctor = ctorInit->get_ctor() ) { 430 if ( objDecl->get_storageClass() == DeclarationNode::Static ) { 431 // generate: 432 // static bool __objName_uninitialized = true; 433 // if (__objName_uninitialized) { 434 // __ctor(__objName); 435 // void dtor_atexit() { 436 // __dtor(__objName); 437 // } 438 // on_exit(dtorOnExit, &__objName); 439 // __objName_uninitialized = false; 440 // } 441 442 // generate first line 443 BasicType * boolType = new BasicType( Type::Qualifiers(), BasicType::Bool ); 444 SingleInit * boolInitExpr = new SingleInit( new ConstantExpr( Constant( boolType->clone(), "1" ) ), noDesignators ); 445 ObjectDecl * isUninitializedVar = new ObjectDecl( objDecl->get_mangleName() + "_uninitialized", DeclarationNode::Static, LinkageSpec::Cforall, 0, boolType, boolInitExpr ); 446 isUninitializedVar->fixUniqueId(); 447 448 // void dtor_atexit(...) {...} 449 FunctionDecl * dtorCaller = new FunctionDecl( objDecl->get_mangleName() + "_dtor_atexit", DeclarationNode::NoStorageClass, LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt( noLabels ), false, false ); 450 dtorCaller->fixUniqueId(); 451 dtorCaller->get_statements()->get_kids().push_back( ctorInit->get_dtor() ); 452 453 // on_exit(dtor_atexit); 454 UntypedExpr * callAtexit = new UntypedExpr( new NameExpr( "atexit" ) ); 455 callAtexit->get_args().push_back( new VariableExpr( dtorCaller ) ); 456 457 // __objName_uninitialized = false; 458 UntypedExpr * setTrue = new UntypedExpr( new NameExpr( "?=?" ) ); 459 setTrue->get_args().push_back( new VariableExpr( isUninitializedVar ) ); 460 setTrue->get_args().push_back( new ConstantExpr( Constant( boolType->clone(), "0" ) ) ); 461 462 // generate body of if 463 CompoundStmt * initStmts = new CompoundStmt( noLabels ); 464 std::list< Statement * > & body = initStmts->get_kids(); 465 body.push_back( ctor ); 466 body.push_back( new DeclStmt( noLabels, dtorCaller ) ); 467 body.push_back( new ExprStmt( noLabels, callAtexit ) ); 468 body.push_back( new ExprStmt( noLabels, setTrue ) ); 469 470 // put it all together 471 IfStmt * ifStmt = new IfStmt( noLabels, new VariableExpr( isUninitializedVar ), initStmts, 0 ); 472 stmtsToAddAfter.push_back( new DeclStmt( noLabels, isUninitializedVar ) ); 473 stmtsToAddAfter.push_back( ifStmt ); 474 } else { 475 stmtsToAddAfter.push_back( ctor ); 476 } 477 objDecl->set_init( NULL ); 478 ctorInit->set_ctor( NULL ); 479 } else if ( Initializer * init = ctorInit->get_init() ) { 480 objDecl->set_init( init ); 481 ctorInit->set_init( NULL ); 383 482 } else { 384 stmtsToAddAfter.push_back( ctor );385 dtorStmts.back().push_front( ctorInit->get_dtor());483 // no constructor and no initializer, which is okay 484 objDecl->set_init( NULL ); 386 485 } 387 objDecl->set_init( NULL ); 388 ctorInit->set_ctor( NULL ); 389 ctorInit->set_dtor( NULL ); // xxx - only destruct when constructing? Probably not? 390 } else if ( Initializer * init = ctorInit->get_init() ) { 391 objDecl->set_init( init ); 392 ctorInit->set_init( NULL ); 393 } else { 394 // no constructor and no initializer, which is okay 395 objDecl->set_init( NULL ); 396 } 397 delete ctorInit; 398 } 399 return objDecl; 400 } 401 402 namespace { 486 delete ctorInit; 487 } 488 return objDecl; 489 } 490 491 void ObjDeclCollector::visit( CompoundStmt *compoundStmt ) { 492 std::set< ObjectDecl * > prevVars = curVars; 493 Parent::visit( compoundStmt ); 494 curVars = prevVars; 495 } 496 497 void ObjDeclCollector::visit( DeclStmt *stmt ) { 498 // keep track of all variables currently in scope 499 if ( ObjectDecl * objDecl = dynamic_cast< ObjectDecl * > ( stmt->get_decl() ) ) { 500 curVars.insert( objDecl ); 501 } 502 Parent::visit( stmt ); 503 } 504 505 void LabelFinder::handleStmt( Statement * stmt ) { 506 // for each label, remember the variables in scope at that label. 507 for ( Label l : stmt->get_labels() ) { 508 vars[l] = curVars; 509 } 510 } 511 403 512 template<typename Iterator, typename OutputIterator> 404 513 void insertDtors( Iterator begin, Iterator end, OutputIterator out ) { 405 514 for ( Iterator it = begin ; it != end ; ++it ) { 406 // remove if instrinsic destructor statement. Note that this is only called 407 // on lists of implicit dtors, so if the user manually calls an intrinsic 408 // dtor then the call must (and will) still be generated since the argument 409 // may contain side effects. 410 if ( ! isInstrinsicSingleArgCallStmt( *it ) ) { 411 // don't need to call intrinsic dtor, because it does nothing, but 412 // non-intrinsic dtors must be called 413 *out++ = (*it)->clone(); 515 // extract destructor statement from the object decl and 516 // insert it into the output. Note that this is only called 517 // on lists of non-static objects with implicit non-intrinsic 518 // dtors, so if the user manually calls an intrinsic dtor 519 // then the call must (and will) still be generated since 520 // the argument may contain side effects. 521 ObjectDecl * objDecl = *it; 522 ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ); 523 assert( ctorInit && ctorInit->get_dtor() ); 524 *out++ = ctorInit->get_dtor()->clone(); 525 } 526 } 527 528 void InsertDtors::visit( ObjectDecl * objDecl ) { 529 // remember non-static destructed objects so that their destructors can be inserted later 530 if ( objDecl->get_storageClass() != DeclarationNode::Static ) { 531 if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) { 532 // a decision should have been made by the resolver, so ctor and init are not both non-NULL 533 assert( ! ctorInit->get_ctor() || ! ctorInit->get_init() ); 534 Statement * dtor = ctorInit->get_dtor(); 535 if ( dtor && ! isInstrinsicSingleArgCallStmt( dtor ) ) { 536 // don't need to call intrinsic dtor, because it does nothing, but 537 // non-intrinsic dtors must be called 538 reverseDeclOrder.front().push_front( objDecl ); 539 } 414 540 } 415 541 } 416 } 417 } 418 419 CompoundStmt * FixInit::mutate( CompoundStmt * compoundStmt ) { 420 // mutate statements - this will also populate dtorStmts list. 421 // don't want to dump all destructors when block is left, 422 // just the destructors associated with variables defined in this block, 423 // so push a new list to the top of the stack so that we can differentiate scopes 424 dtorStmts.push_back( std::list<Statement *>() ); 425 426 compoundStmt = PolyMutator::mutate( compoundStmt ); 427 std::list< Statement * > & statements = compoundStmt->get_kids(); 428 429 insertDtors( dtorStmts.back().begin(), dtorStmts.back().end(), back_inserter( statements ) ); 430 431 deleteAll( dtorStmts.back() ); 432 dtorStmts.pop_back(); 433 return compoundStmt; 434 } 435 436 Statement * FixInit::mutate( ReturnStmt * returnStmt ) { 437 for ( std::list< std::list< Statement * > >::reverse_iterator list = dtorStmts.rbegin(); list != dtorStmts.rend(); ++list ) { 438 insertDtors( list->begin(), list->end(), back_inserter( stmtsToAdd ) ); 439 } 440 return Mutator::mutate( returnStmt ); 441 } 442 443 Statement * FixInit::mutate( BranchStmt * branchStmt ) { 444 // TODO: adding to the end of a block isn't sufficient, since 445 // return/break/goto should trigger destructor when block is left. 446 switch( branchStmt->get_type() ) { 447 case BranchStmt::Continue: 448 case BranchStmt::Break: 449 insertDtors( dtorStmts.back().begin(), dtorStmts.back().end(), back_inserter( stmtsToAdd ) ); 450 break; 451 case BranchStmt::Goto: 452 // xxx 453 // if goto leaves a block, generate dtors for every block it leaves 454 // if goto is in same block but earlier statement, destruct every object that was defined after the statement 455 break; 456 default: 457 assert( false ); 458 } 459 return Mutator::mutate( branchStmt ); 460 } 461 462 542 Parent::visit( objDecl ); 543 } 544 545 void InsertDtors::visit( CompoundStmt * compoundStmt ) { 546 // visit statements - this will also populate reverseDeclOrder list. 547 // don't want to dump all destructors when block is left, 548 // just the destructors associated with variables defined in this block, 549 // so push a new list to the top of the stack so that we can differentiate scopes 550 reverseDeclOrder.push_front( OrderedDecls() ); 551 Parent::visit( compoundStmt ); 552 553 // add destructors for the current scope that we're exiting 554 std::list< Statement * > & statements = compoundStmt->get_kids(); 555 insertDtors( reverseDeclOrder.front().begin(), reverseDeclOrder.front().end(), back_inserter( statements ) ); 556 reverseDeclOrder.pop_front(); 557 } 558 559 void InsertDtors::visit( ReturnStmt * returnStmt ) { 560 // return exits all scopes, so dump destructors for all scopes 561 for ( OrderedDecls & od : reverseDeclOrder ) { 562 insertDtors( od.begin(), od.end(), back_inserter( stmtsToAdd ) ); 563 } 564 } 565 566 // Handle break/continue/goto in the same manner as C++. 567 // Basic idea: any objects that are in scope at the BranchStmt 568 // but not at the labelled (target) statement must be destructed. 569 // If there are any objects in scope at the target location but 570 // not at the BranchStmt then those objects would be uninitialized 571 // so notify the user of the error. 572 // See C++ Reference 6.6 Jump Statements for details. 573 void InsertDtors::handleGoto( BranchStmt * stmt ) { 574 assert( stmt->get_target() != "" && "BranchStmt missing a label" ); 575 // S_L = lvars = set of objects in scope at label definition 576 // S_G = curVars = set of objects in scope at goto statement 577 ObjectSet & lvars = labelVars[ stmt->get_target() ]; 578 579 DTOR_PRINT( 580 std::cerr << "at goto label: " << stmt->get_target().get_name() << std::endl; 581 std::cerr << "S_G = " << printSet( curVars ) << std::endl; 582 std::cerr << "S_L = " << printSet( lvars ) << std::endl; 583 ) 584 585 ObjectSet diff; 586 // S_L-S_G results in set of objects whose construction is skipped - it's an error if this set is non-empty 587 std::set_difference( lvars.begin(), lvars.end(), curVars.begin(), curVars.end(), std::inserter( diff, diff.begin() ) ); 588 DTOR_PRINT( 589 std::cerr << "S_L-S_G = " << printSet( diff ) << std::endl; 590 ) 591 if ( ! diff.empty() ) { 592 throw SemanticError( std::string("jump to label '") + stmt->get_target().get_name() + "' crosses initialization of " + (*diff.begin())->get_name() + " ", stmt ); 593 } 594 // S_G-S_L results in set of objects that must be destructed 595 diff.clear(); 596 std::set_difference( curVars.begin(), curVars.end(), lvars.begin(), lvars.end(), std::inserter( diff, diff.end() ) ); 597 DTOR_PRINT( 598 std::cerr << "S_G-S_L = " << printSet( diff ) << std::endl; 599 ) 600 if ( ! diff.empty() ) { 601 // go through decl ordered list of objectdecl. for each element that occurs in diff, output destructor 602 OrderedDecls ordered; 603 for ( OrderedDecls & rdo : reverseDeclOrder ) { 604 // add elements from reverseDeclOrder into ordered if they occur in diff - it is key that this happens in reverse declaration order. 605 copy_if( rdo.begin(), rdo.end(), back_inserter( ordered ), [&]( ObjectDecl * objDecl ) { return diff.count( objDecl ); } ); 606 } 607 insertDtors( ordered.begin(), ordered.end(), back_inserter( stmtsToAdd ) ); 608 } 609 } 610 611 void InsertDtors::visit( BranchStmt * stmt ) { 612 switch( stmt->get_type() ) { 613 case BranchStmt::Continue: 614 case BranchStmt::Break: 615 // could optimize the break/continue case, because the S_L-S_G check 616 // is unnecessary (this set should always be empty), but it serves 617 // as a small sanity check. 618 case BranchStmt::Goto: 619 handleGoto( stmt ); 620 break; 621 default: 622 assert( false ); 623 } 624 } 625 } // namespace 463 626 } // namespace InitTweak 464 627 -
src/InitTweak/InitTweak.cc
r7305915 r87b5bf0 115 115 116 116 namespace { 117 template<typename CallExpr> 118 std::string funcName( CallExpr * expr ) { 119 Expression * func = expr->get_function(); 117 std::string funcName( Expression * func ) { 120 118 if ( NameExpr * nameExpr = dynamic_cast< NameExpr * >( func ) ) { 121 119 return nameExpr->get_name(); 122 120 } else if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( func ) ) { 123 121 return varExpr->get_var()->get_name(); 122 } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( func ) ) { 123 return funcName( castExpr->get_arg() ); 124 124 } else { 125 125 assert( false && "Unexpected expression type being called as a function in call expression" ); … … 130 130 std::string getFunctionName( Expression * expr ) { 131 131 if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr ) ) { 132 return funcName( appExpr );132 return funcName( appExpr->get_function() ); 133 133 } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * > ( expr ) ) { 134 return funcName( untypedExpr );134 return funcName( untypedExpr->get_function() ); 135 135 } else { 136 std::cerr << expr << std::endl; 136 137 assert( false && "Unexpected expression type passed to getFunctionName" ); 137 138 } -
src/Makefile.in
r7305915 r87b5bf0 194 194 SynTree/driver_cfa_cpp-Visitor.$(OBJEXT) \ 195 195 SynTree/driver_cfa_cpp-Mutator.$(OBJEXT) \ 196 SynTree/driver_cfa_cpp-AddStmtVisitor.$(OBJEXT) \ 196 197 SynTree/driver_cfa_cpp-TypeSubstitution.$(OBJEXT) \ 197 198 SynTree/driver_cfa_cpp-Attribute.$(OBJEXT) \ … … 412 413 SynTree/NamedTypeDecl.cc SynTree/TypeDecl.cc \ 413 414 SynTree/Initializer.cc SynTree/Visitor.cc SynTree/Mutator.cc \ 414 SynTree/ TypeSubstitution.cc SynTree/Attribute.cc \415 Tuples/Mutate.cc Tuples/AssignExpand.cc \415 SynTree/AddStmtVisitor.cc SynTree/TypeSubstitution.cc \ 416 SynTree/Attribute.cc Tuples/Mutate.cc Tuples/AssignExpand.cc \ 416 417 Tuples/FunctionFixer.cc Tuples/TupleAssignment.cc \ 417 418 Tuples/FunctionChecker.cc Tuples/NameMatcher.cc … … 782 783 SynTree/driver_cfa_cpp-Mutator.$(OBJEXT): SynTree/$(am__dirstamp) \ 783 784 SynTree/$(DEPDIR)/$(am__dirstamp) 785 SynTree/driver_cfa_cpp-AddStmtVisitor.$(OBJEXT): \ 786 SynTree/$(am__dirstamp) SynTree/$(DEPDIR)/$(am__dirstamp) 784 787 SynTree/driver_cfa_cpp-TypeSubstitution.$(OBJEXT): \ 785 788 SynTree/$(am__dirstamp) SynTree/$(DEPDIR)/$(am__dirstamp) … … 878 881 -rm -f SymTab/driver_cfa_cpp-TypeEquality.$(OBJEXT) 879 882 -rm -f SymTab/driver_cfa_cpp-Validate.$(OBJEXT) 883 -rm -f SynTree/driver_cfa_cpp-AddStmtVisitor.$(OBJEXT) 880 884 -rm -f SynTree/driver_cfa_cpp-AddressExpr.$(OBJEXT) 881 885 -rm -f SynTree/driver_cfa_cpp-AggregateDecl.$(OBJEXT) … … 988 992 @AMDEP_TRUE@@am__include@ @am__quote@SymTab/$(DEPDIR)/driver_cfa_cpp-TypeEquality.Po@am__quote@ 989 993 @AMDEP_TRUE@@am__include@ @am__quote@SymTab/$(DEPDIR)/driver_cfa_cpp-Validate.Po@am__quote@ 994 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-AddStmtVisitor.Po@am__quote@ 990 995 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-AddressExpr.Po@am__quote@ 991 996 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-AggregateDecl.Po@am__quote@ … … 2415 2420 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 2416 2421 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o SynTree/driver_cfa_cpp-Mutator.obj `if test -f 'SynTree/Mutator.cc'; then $(CYGPATH_W) 'SynTree/Mutator.cc'; else $(CYGPATH_W) '$(srcdir)/SynTree/Mutator.cc'; fi` 2422 2423 SynTree/driver_cfa_cpp-AddStmtVisitor.o: SynTree/AddStmtVisitor.cc 2424 @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT SynTree/driver_cfa_cpp-AddStmtVisitor.o -MD -MP -MF SynTree/$(DEPDIR)/driver_cfa_cpp-AddStmtVisitor.Tpo -c -o SynTree/driver_cfa_cpp-AddStmtVisitor.o `test -f 'SynTree/AddStmtVisitor.cc' || echo '$(srcdir)/'`SynTree/AddStmtVisitor.cc 2425 @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) SynTree/$(DEPDIR)/driver_cfa_cpp-AddStmtVisitor.Tpo SynTree/$(DEPDIR)/driver_cfa_cpp-AddStmtVisitor.Po 2426 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='SynTree/AddStmtVisitor.cc' object='SynTree/driver_cfa_cpp-AddStmtVisitor.o' libtool=no @AMDEPBACKSLASH@ 2427 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 2428 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o SynTree/driver_cfa_cpp-AddStmtVisitor.o `test -f 'SynTree/AddStmtVisitor.cc' || echo '$(srcdir)/'`SynTree/AddStmtVisitor.cc 2429 2430 SynTree/driver_cfa_cpp-AddStmtVisitor.obj: SynTree/AddStmtVisitor.cc 2431 @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT SynTree/driver_cfa_cpp-AddStmtVisitor.obj -MD -MP -MF SynTree/$(DEPDIR)/driver_cfa_cpp-AddStmtVisitor.Tpo -c -o SynTree/driver_cfa_cpp-AddStmtVisitor.obj `if test -f 'SynTree/AddStmtVisitor.cc'; then $(CYGPATH_W) 'SynTree/AddStmtVisitor.cc'; else $(CYGPATH_W) '$(srcdir)/SynTree/AddStmtVisitor.cc'; fi` 2432 @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) SynTree/$(DEPDIR)/driver_cfa_cpp-AddStmtVisitor.Tpo SynTree/$(DEPDIR)/driver_cfa_cpp-AddStmtVisitor.Po 2433 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='SynTree/AddStmtVisitor.cc' object='SynTree/driver_cfa_cpp-AddStmtVisitor.obj' libtool=no @AMDEPBACKSLASH@ 2434 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 2435 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o SynTree/driver_cfa_cpp-AddStmtVisitor.obj `if test -f 'SynTree/AddStmtVisitor.cc'; then $(CYGPATH_W) 'SynTree/AddStmtVisitor.cc'; else $(CYGPATH_W) '$(srcdir)/SynTree/AddStmtVisitor.cc'; fi` 2417 2436 2418 2437 SynTree/driver_cfa_cpp-TypeSubstitution.o: SynTree/TypeSubstitution.cc -
src/Parser/ExpressionNode.cc
r7305915 r87b5bf0 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // ExpressionNode.cc -- 8 // 7 // ExpressionNode.cc -- 8 // 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Sat May 16 13:17:07 2015 … … 12 12 // Last Modified On : Mon Jun 13 14:46:17 2016 13 13 // Update Count : 307 14 // 14 // 15 15 16 16 #include <cassert> … … 231 231 // "abc" "def" "ghi" => "abcdefghi", remove new text from quotes and insert before last quote in old string. 232 232 value.insert( value.length() - 1, newValue->substr( 1, newValue->length() - 2 ) ); 233 233 234 234 delete newValue; // allocated by lexer 235 235 return this; … … 347 347 348 348 if ( isArrayIndex ) { 349 // need to traverse entire structure and change any instances of 0 or 1 to 349 // need to traverse entire structure and change any instances of 0 or 1 to 350 350 // ConstantExpr 351 351 DesignatorFixer fixer; … … 440 440 } 441 441 442 CompositeExprNode::CompositeExprNode( const CompositeExprNode &other ) : ExpressionNode( other ), function( maybeClone( other.function ) ) {442 CompositeExprNode::CompositeExprNode( const CompositeExprNode &other ) : ExpressionNode( other ), function( maybeClone( other.function ) ), arguments( 0 ) { 443 443 ParseNode *cur = other.arguments; 444 444 while ( cur ) { … … 608 608 { 609 609 assert( args.size() == 2 ); 610 610 611 611 if ( TypeValueNode * arg = dynamic_cast<TypeValueNode *>( get_args() ) ) { 612 612 NameExpr *member = dynamic_cast<NameExpr *>( args.back() ); -
src/Parser/ParseNode.h
r7305915 r87b5bf0 28 28 //#include "SynTree/Declaration.h" 29 29 #include "Common/UniqueName.h" 30 #include "SynTree/Label.h" 30 31 31 32 class ExpressionNode; … … 284 285 virtual void printOneLine( std::ostream &, int indent = 0) const; 285 286 286 const std::list< std::string> &get_labels() const { return labels; };287 const std::list< Label > &get_labels() const { return labels; }; 287 288 void append_label( std::string *label ) { labels.push_back( *label ); delete label; } 288 289 private: 289 std::list< std::string> labels;290 std::list< Label > labels; 290 291 }; 291 292 … … 532 533 ExpressionNode *output, *input; 533 534 ConstantNode *clobber; 534 std::list< std::string> gotolabels;535 std::list< Label > gotolabels; 535 536 }; 536 537 -
src/Parser/StatementNode.cc
r7305915 r87b5bf0 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // StatementNode.cc -- 7 // StatementNode.cc -- 8 8 // 9 9 // Author : Rodolfo G. Esteves … … 27 27 28 28 const char *StatementNode::StType[] = { 29 "Exp", "If", "Switch", "Case", "Default", "Choose", "Fallthru", 30 "While", "Do", "For", 29 "Exp", "If", "Switch", "Case", "Default", "Choose", "Fallthru", 30 "While", "Do", "For", 31 31 "Goto", "Continue", "Break", "Return", "Throw", 32 32 "Try", "Catch", "Finally", "Asm", … … 62 62 StatementNode::StatementNode( Type t, ExpressionNode *ctrl_label, StatementNode *block ) : type( t ), control( ctrl_label ), block( block ), labels( 0 ), target( 0 ), decl( 0 ), isCatchRest ( false ) { 63 63 this->control = ( t == Default ) ? 0 : control; 64 } 64 } 65 65 66 66 StatementNode::StatementNode( Type t, string *target ) : type( t ), control( 0 ), block( 0 ), labels( 0 ), target( target ), decl( 0 ), isCatchRest ( false ) {} … … 74 74 75 75 StatementNode * StatementNode::newCatchStmt( DeclarationNode *d, StatementNode *s, bool catchRestP ) { 76 StatementNode *ret = new StatementNode( StatementNode::Catch, 0, s ); 76 StatementNode *ret = new StatementNode( StatementNode::Catch, 0, s ); 77 77 ret->addDeclaration( d ); 78 78 ret->setCatchRest( catchRestP ); … … 101 101 StatementNode *StatementNode::add_label( const std::string *l ) { 102 102 if ( l != 0 ) { 103 labels.push_front( *l ); 103 labels.push_front( *l ); 104 104 delete l; 105 105 } // if … … 156 156 control->print( os, indent ); 157 157 os << endl; 158 } else 158 } else 159 159 os << string( indent, ' ' ) << "Null Statement" << endl; 160 160 break; … … 177 177 if ( block ) { 178 178 os << string( indent + ParseNode::indent_by, ' ' ) << "Branches of execution: " << endl; 179 block->printList( os, indent + 2 * ParseNode::indent_by ); 179 block->printList( os, indent + 2 * ParseNode::indent_by ); 180 180 } // if 181 181 if ( target ) { … … 258 258 case Fallthru: 259 259 return new FallthruStmt( labs ); 260 case Case: 260 case Case: 261 261 return new CaseStmt( labs, maybeBuild<Expression>(get_control()), branches ); 262 262 case Default: … … 394 394 os << string( indent + ParseNode::indent_by, ' ' ) << "Goto Labels:" << endl; 395 395 os << string( indent + 2 * ParseNode::indent_by, ' ' ); 396 for ( std::list< std::string>::const_iterator i = gotolabels.begin();; ) {396 for ( std::list<Label>::const_iterator i = gotolabels.begin();; ) { 397 397 os << *i; 398 398 i++; … … 426 426 } 427 427 428 Statement *NullStmtNode::build() const { 428 Statement *NullStmtNode::build() const { 429 429 return new NullStmt; 430 430 } -
src/ResolvExpr/Resolver.cc
r7305915 r87b5bf0 503 503 delete ctorInit->get_ctor(); 504 504 ctorInit->set_ctor( NULL ); 505 delete ctorInit->get_dtor(); 506 ctorInit->set_dtor( NULL ); 505 507 maybeAccept( ctorInit->get_init(), *this ); 506 508 } -
src/SymTab/Autogen.cc
r7305915 r87b5bf0 482 482 ObjectDecl *dst = new ObjectDecl( "_dst", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), typeInst->clone() ), 0 ); 483 483 if ( typeDecl->get_base() ) { 484 // xxx - generate ctor/dtors for typedecls, e.g. 485 // otype T = int *; 484 486 stmts = new CompoundStmt( std::list< Label >() ); 485 487 UntypedExpr *assign = new UntypedExpr( new NameExpr( "?=?" ) ); -
src/SymTab/Autogen.h
r7305915 r87b5bf0 24 24 25 25 namespace SymTab { 26 static const std::list< std::string > noLabels;27 28 26 /// Generates assignment operators, constructors, and destructor for aggregate types as required 29 27 void autogenerateRoutines( std::list< Declaration * > &translationUnit ); -
src/SymTab/Indexer.h
r7305915 r87b5bf0 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // Indexer.h -- 7 // Indexer.h -- 8 8 // 9 9 // Author : Richard C. Bilson … … 33 33 Indexer& operator= ( Indexer &&that ); 34 34 35 //using Visitor::visit;35 using Visitor::visit; 36 36 virtual void visit( ObjectDecl *objectDecl ); 37 37 virtual void visit( FunctionDecl *functionDecl ); … … 54 54 virtual void visit( MemberExpr *memberExpr ); 55 55 virtual void visit( VariableExpr *variableExpr ); 56 virtual void visit( ConstantExpr *constantExpr ); 56 virtual void visit( ConstantExpr *constantExpr ); 57 57 virtual void visit( SizeofExpr *sizeofExpr ); 58 58 virtual void visit( AlignofExpr *alignofExpr ); … … 93 93 /// Gets the top-most trait declaration with the given ID 94 94 TraitDecl *lookupTrait( const std::string &id ) const; 95 95 96 96 void print( std::ostream &os, int indent = 0 ) const; 97 97 private: … … 106 106 UnionDecl *lookupUnionAtScope( const std::string &id, unsigned long scope ) const; 107 107 TraitDecl *lookupTraitAtScope( const std::string &id, unsigned long scope ) const; 108 108 109 109 void addId( DeclarationWithType *decl ); 110 110 void addType( NamedTypeDecl *decl ); … … 115 115 void addUnion( UnionDecl *decl ); 116 116 void addTrait( TraitDecl *decl ); 117 117 118 118 struct Impl; 119 119 Impl *tables; ///< Copy-on-write instance of table data structure -
src/SynTree/Statement.cc
r7305915 r87b5bf0 87 87 Statement( labels ), originalTarget( _target ), target( _target ), computedTarget( NULL ), type( _type ) { 88 88 //actually this is a syntactic error signaled by the parser 89 if ( type == BranchStmt::Goto && target. size() == 0)89 if ( type == BranchStmt::Goto && target.empty() ) 90 90 throw SemanticError("goto without target"); 91 91 } -
src/SynTree/Statement.h
r7305915 r87b5bf0 22 22 #include "Common/SemanticError.h" 23 23 #include "Type.h" 24 #include "Label.h" 24 25 25 26 class Statement { -
src/SynTree/SynTree.h
r7305915 r87b5bf0 113 113 class Constant; 114 114 115 typedef std::string Label; 115 // typedef std::string Label; 116 class Label; 116 117 typedef unsigned int UniqueId; 117 118 -
src/SynTree/Visitor.cc
r7305915 r87b5bf0 39 39 } 40 40 41 void Visitor:: visit( AggregateDecl *aggregateDecl ) {41 void Visitor::handleAggregateDecl( AggregateDecl *aggregateDecl ) { 42 42 acceptAll( aggregateDecl->get_parameters(), *this ); 43 43 acceptAll( aggregateDecl->get_members(), *this ); … … 45 45 46 46 void Visitor::visit( StructDecl *aggregateDecl ) { 47 visit( static_cast< AggregateDecl* >( aggregateDecl ) );47 handleAggregateDecl( static_cast< AggregateDecl* >( aggregateDecl ) ); 48 48 } 49 49 50 50 void Visitor::visit( UnionDecl *aggregateDecl ) { 51 visit( static_cast< AggregateDecl* >( aggregateDecl ) );51 handleAggregateDecl( static_cast< AggregateDecl* >( aggregateDecl ) ); 52 52 } 53 53 54 54 void Visitor::visit( EnumDecl *aggregateDecl ) { 55 visit( static_cast< AggregateDecl* >( aggregateDecl ) );55 handleAggregateDecl( static_cast< AggregateDecl* >( aggregateDecl ) ); 56 56 } 57 57 58 58 void Visitor::visit( TraitDecl *aggregateDecl ) { 59 visit( static_cast< AggregateDecl* >( aggregateDecl ) );60 } 61 62 void Visitor:: visit( NamedTypeDecl *typeDecl ) {59 handleAggregateDecl( static_cast< AggregateDecl* >( aggregateDecl ) ); 60 } 61 62 void Visitor::handleNamedTypeDecl( NamedTypeDecl *typeDecl ) { 63 63 acceptAll( typeDecl->get_parameters(), *this ); 64 64 acceptAll( typeDecl->get_assertions(), *this ); … … 67 67 68 68 void Visitor::visit( TypeDecl *typeDecl ) { 69 visit( static_cast< NamedTypeDecl* >( typeDecl ) );69 handleNamedTypeDecl( static_cast< NamedTypeDecl* >( typeDecl ) ); 70 70 } 71 71 72 72 void Visitor::visit( TypedefDecl *typeDecl ) { 73 visit( static_cast< NamedTypeDecl* >( typeDecl ) );73 handleNamedTypeDecl( static_cast< NamedTypeDecl* >( typeDecl ) ); 74 74 } 75 75 … … 330 330 } 331 331 332 void Visitor:: visit( ReferenceToType *aggregateUseType ) {332 void Visitor::handleReferenceToType( ReferenceToType *aggregateUseType ) { 333 333 acceptAll( aggregateUseType->get_forall(), *this ); 334 334 acceptAll( aggregateUseType->get_parameters(), *this ); … … 336 336 337 337 void Visitor::visit( StructInstType *aggregateUseType ) { 338 visit( static_cast< ReferenceToType * >( aggregateUseType ) );338 handleReferenceToType( static_cast< ReferenceToType * >( aggregateUseType ) ); 339 339 } 340 340 341 341 void Visitor::visit( UnionInstType *aggregateUseType ) { 342 visit( static_cast< ReferenceToType * >( aggregateUseType ) );342 handleReferenceToType( static_cast< ReferenceToType * >( aggregateUseType ) ); 343 343 } 344 344 345 345 void Visitor::visit( EnumInstType *aggregateUseType ) { 346 visit( static_cast< ReferenceToType * >( aggregateUseType ) );346 handleReferenceToType( static_cast< ReferenceToType * >( aggregateUseType ) ); 347 347 } 348 348 349 349 void Visitor::visit( TraitInstType *aggregateUseType ) { 350 visit( static_cast< ReferenceToType * >( aggregateUseType ) );350 handleReferenceToType( static_cast< ReferenceToType * >( aggregateUseType ) ); 351 351 acceptAll( aggregateUseType->get_members(), *this ); 352 352 } 353 353 354 354 void Visitor::visit( TypeInstType *aggregateUseType ) { 355 visit( static_cast< ReferenceToType * >( aggregateUseType ) );355 handleReferenceToType( static_cast< ReferenceToType * >( aggregateUseType ) ); 356 356 } 357 357 -
src/SynTree/Visitor.h
r7305915 r87b5bf0 104 104 virtual void visit( Constant *constant ); 105 105 private: 106 virtual void visit( AggregateDecl *aggregateDecl );107 virtual void visit( NamedTypeDecl *typeDecl );108 virtual void visit( ReferenceToType *aggregateUseType );106 virtual void handleAggregateDecl( AggregateDecl *aggregateDecl ); 107 virtual void handleNamedTypeDecl( NamedTypeDecl *typeDecl ); 108 virtual void handleReferenceToType( ReferenceToType *aggregateUseType ); 109 109 }; 110 110 -
src/SynTree/module.mk
r7305915 r87b5bf0 46 46 SynTree/Visitor.cc \ 47 47 SynTree/Mutator.cc \ 48 SynTree/AddStmtVisitor.cc \ 48 49 SynTree/TypeSubstitution.cc \ 49 50 SynTree/Attribute.cc -
src/tests/Makefile.am
r7305915 r87b5bf0 27 27 28 28 all-local : 29 +python test.py vector_test avl_test operators numericConstants expression enum asmName array typeof cast 29 +python test.py vector_test avl_test operators numericConstants expression enum asmName array typeof cast dtor-early-exit init_once 30 30 31 31 all-tests : … … 46 46 constant0-1NDDP : constant0-1.c 47 47 ${CC} ${CFLAGS} -DNEWDECL -DDUPS ${<} -o ${@} 48 49 dtor-early-exit-ERR1: dtor-early-exit.c 50 ${CC} ${CFLAGS} -DERR1 ${<} -o ${@} 51 52 dtor-early-exit-ERR2: dtor-early-exit.c 53 ${CC} ${CFLAGS} -DERR2 ${<} -o ${@} 54 -
src/tests/Makefile.in
r7305915 r87b5bf0 634 634 635 635 all-local : 636 +python test.py vector_test avl_test operators numericConstants expression enum asmName array typeof cast 636 +python test.py vector_test avl_test operators numericConstants expression enum asmName array typeof cast dtor-early-exit init_once 637 637 638 638 all-tests : … … 653 653 constant0-1NDDP : constant0-1.c 654 654 ${CC} ${CFLAGS} -DNEWDECL -DDUPS ${<} -o ${@} 655 656 dtor-early-exit-ERR1: dtor-early-exit.c 657 ${CC} ${CFLAGS} -DERR1 ${<} -o ${@} 658 659 dtor-early-exit-ERR2: dtor-early-exit.c 660 ${CC} ${CFLAGS} -DERR2 ${<} -o ${@} 655 661 656 662 # Tell versions [3.59,3.63) of GNU make to not export all variables.
Note: See TracChangeset
for help on using the changeset viewer.