| [71f4e4f] | 1 | //
 | 
|---|
 | 2 | // Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
 | 
|---|
 | 3 | //
 | 
|---|
 | 4 | // The contents of this file are covered under the licence agreement in the
 | 
|---|
 | 5 | // file "LICENCE" distributed with Cforall.
 | 
|---|
 | 6 | //
 | 
|---|
| [9fe33947] | 7 | // FixInit.cc --
 | 
|---|
| [71f4e4f] | 8 | //
 | 
|---|
 | 9 | // Author           : Rob Schluntz
 | 
|---|
 | 10 | // Created On       : Wed Jan 13 16:29:30 2016
 | 
|---|
| [adcc065] | 11 | // Last Modified By : Peter A. Buhr
 | 
|---|
| [d56e5bc] | 12 | // Last Modified On : Wed Jun 21 17:35:05 2017
 | 
|---|
 | 13 | // Update Count     : 74
 | 
|---|
| [71f4e4f] | 14 | //
 | 
|---|
| [be9288a] | 15 | #include "FixInit.h"
 | 
|---|
| [71f4e4f] | 16 | 
 | 
|---|
| [d180746] | 17 | #include <stddef.h>                    // for NULL
 | 
|---|
 | 18 | #include <algorithm>                   // for set_difference, copy_if
 | 
|---|
| [e3e16bc] | 19 | #include <cassert>                     // for assert, strict_dynamic_cast
 | 
|---|
| [d180746] | 20 | #include <iostream>                    // for operator<<, ostream, basic_ost...
 | 
|---|
 | 21 | #include <iterator>                    // for insert_iterator, back_inserter
 | 
|---|
 | 22 | #include <list>                        // for _List_iterator, list, list<>::...
 | 
|---|
 | 23 | #include <map>                         // for _Rb_tree_iterator, _Rb_tree_co...
 | 
|---|
 | 24 | #include <memory>                      // for allocator_traits<>::value_type
 | 
|---|
 | 25 | #include <set>                         // for set, set<>::value_type
 | 
|---|
 | 26 | #include <unordered_map>               // for unordered_map, unordered_map<>...
 | 
|---|
 | 27 | #include <unordered_set>               // for unordered_set
 | 
|---|
 | 28 | #include <utility>                     // for pair
 | 
|---|
| [134322e] | 29 | 
 | 
|---|
| [d180746] | 30 | #include "CodeGen/GenType.h"           // for genPrettyType
 | 
|---|
| [bff227f] | 31 | #include "CodeGen/OperatorTable.h"
 | 
|---|
| [d180746] | 32 | #include "Common/PassVisitor.h"        // for PassVisitor, WithStmtsToAdd
 | 
|---|
 | 33 | #include "Common/SemanticError.h"      // for SemanticError
 | 
|---|
 | 34 | #include "Common/UniqueName.h"         // for UniqueName
 | 
|---|
 | 35 | #include "Common/utility.h"            // for CodeLocation, ValueGuard, toSt...
 | 
|---|
 | 36 | #include "FixGlobalInit.h"             // for fixGlobalInit
 | 
|---|
 | 37 | #include "GenInit.h"                   // for genCtorDtor
 | 
|---|
 | 38 | #include "GenPoly/GenPoly.h"           // for getFunctionType
 | 
|---|
 | 39 | #include "InitTweak.h"                 // for getFunctionName, getCallArg
 | 
|---|
 | 40 | #include "Parser/LinkageSpec.h"        // for C, Spec, Cforall, isBuiltin
 | 
|---|
 | 41 | #include "ResolvExpr/Resolver.h"       // for findVoidExpression
 | 
|---|
 | 42 | #include "ResolvExpr/typeops.h"        // for typesCompatible
 | 
|---|
 | 43 | #include "SymTab/Autogen.h"            // for genImplicitCall
 | 
|---|
 | 44 | #include "SymTab/Indexer.h"            // for Indexer
 | 
|---|
 | 45 | #include "SymTab/Mangler.h"            // for Mangler
 | 
|---|
 | 46 | #include "SynTree/Attribute.h"         // for Attribute
 | 
|---|
 | 47 | #include "SynTree/Constant.h"          // for Constant
 | 
|---|
 | 48 | #include "SynTree/Declaration.h"       // for ObjectDecl, FunctionDecl, Decl...
 | 
|---|
 | 49 | #include "SynTree/Expression.h"        // for UniqueExpr, VariableExpr, Unty...
 | 
|---|
 | 50 | #include "SynTree/Initializer.h"       // for ConstructorInit, SingleInit
 | 
|---|
| [ba3706f] | 51 | #include "SynTree/Label.h"             // for Label, operator<
 | 
|---|
| [d180746] | 52 | #include "SynTree/Mutator.h"           // for mutateAll, Mutator, maybeMutate
 | 
|---|
 | 53 | #include "SynTree/Statement.h"         // for ExprStmt, CompoundStmt, Branch...
 | 
|---|
 | 54 | #include "SynTree/Type.h"              // for Type, Type::StorageClasses
 | 
|---|
 | 55 | #include "SynTree/TypeSubstitution.h"  // for TypeSubstitution, operator<<
 | 
|---|
 | 56 | #include "SynTree/Visitor.h"           // for acceptAll, maybeAccept
 | 
|---|
| [71f4e4f] | 57 | 
 | 
|---|
| [f0121d7] | 58 | bool ctordtorp = false; // print all debug
 | 
|---|
 | 59 | bool ctorp = false; // print ctor debug
 | 
|---|
 | 60 | bool cpctorp = false; // print copy ctor debug
 | 
|---|
 | 61 | bool dtorp = false; // print dtor debug
 | 
|---|
| [845cedc] | 62 | #define PRINT( text ) if ( ctordtorp ) { text }
 | 
|---|
| [c2931ea] | 63 | #define CP_CTOR_PRINT( text ) if ( ctordtorp || cpctorp ) { text }
 | 
|---|
 | 64 | #define DTOR_PRINT( text ) if ( ctordtorp || dtorp ) { text }
 | 
|---|
| [845cedc] | 65 | 
 | 
|---|
| [71f4e4f] | 66 | namespace InitTweak {
 | 
|---|
 | 67 |         namespace {
 | 
|---|
| [597db97f] | 68 |                 typedef std::unordered_map< int, int > UnqCount;
 | 
|---|
| [31f379c] | 69 | 
 | 
|---|
| [babeeda] | 70 |                 struct SelfAssignChecker {
 | 
|---|
 | 71 |                         void previsit( ApplicationExpr * appExpr );
 | 
|---|
 | 72 |                 };
 | 
|---|
 | 73 | 
 | 
|---|
| [c0714bf] | 74 |                 struct InsertImplicitCalls : public WithTypeSubstitution {
 | 
|---|
| [adcc065] | 75 |                         /// wrap function application expressions as ImplicitCopyCtorExpr nodes so that it is easy to identify which
 | 
|---|
 | 76 |                         /// function calls need their parameters to be copy constructed
 | 
|---|
| [c0714bf] | 77 |                         static void insert( std::list< Declaration * > & translationUnit );
 | 
|---|
| [134322e] | 78 | 
 | 
|---|
 | 79 |                         Expression * postmutate( ApplicationExpr * appExpr );
 | 
|---|
| [c2931ea] | 80 |                 };
 | 
|---|
 | 81 | 
 | 
|---|
| [c0714bf] | 82 |                 struct ResolveCopyCtors final : public WithIndexer, public WithShortCircuiting, public WithTypeSubstitution {
 | 
|---|
| [adcc065] | 83 |                         /// generate temporary ObjectDecls for each argument and return value of each ImplicitCopyCtorExpr,
 | 
|---|
 | 84 |                         /// generate/resolve copy construction expressions for each, and generate/resolve destructors for both
 | 
|---|
 | 85 |                         /// arguments and return value temporaries
 | 
|---|
| [c0714bf] | 86 |                         static void resolveImplicitCalls( std::list< Declaration * > & translationUnit, UnqCount & unqCount );
 | 
|---|
| [c2931ea] | 87 | 
 | 
|---|
| [c0714bf] | 88 |                         ResolveCopyCtors( UnqCount & unqCount ) : unqCount( unqCount ) {}
 | 
|---|
| [31f379c] | 89 | 
 | 
|---|
| [c0714bf] | 90 |                         void postvisit( ImplicitCopyCtorExpr * impCpCtorExpr );
 | 
|---|
 | 91 |                         void postvisit( StmtExpr * stmtExpr );
 | 
|---|
 | 92 |                         void previsit( UniqueExpr * unqExpr );
 | 
|---|
 | 93 |                         void postvisit( UniqueExpr * unqExpr );
 | 
|---|
| [c2931ea] | 94 | 
 | 
|---|
 | 95 |                         /// create and resolve ctor/dtor expression: fname(var, [cpArg])
 | 
|---|
| [65660bd] | 96 |                         Expression * makeCtorDtor( const std::string & fname, ObjectDecl * var, Expression * cpArg = NULL );
 | 
|---|
| [c2931ea] | 97 |                         /// true if type does not need to be copy constructed to ensure correctness
 | 
|---|
| [1132b62] | 98 |                         bool skipCopyConstruct( Type * type );
 | 
|---|
| [ae1b9ea] | 99 |                         void copyConstructArg( Expression *& arg, ImplicitCopyCtorExpr * impCpCtorExpr, Type * formal );
 | 
|---|
| [092528b] | 100 |                         void destructRet( ObjectDecl * ret, ImplicitCopyCtorExpr * impCpCtorExpr );
 | 
|---|
| [31f379c] | 101 | 
 | 
|---|
| [597db97f] | 102 |                         UnqCount & unqCount; // count the number of times each unique expr ID appears
 | 
|---|
| [c0714bf] | 103 |                         std::unordered_set< int > vars;
 | 
|---|
| [c2931ea] | 104 |                 };
 | 
|---|
 | 105 | 
 | 
|---|
 | 106 |                 /// collects constructed object decls - used as a base class
 | 
|---|
| [698ec72] | 107 |                 struct ObjDeclCollector : public WithGuards, public WithShortCircuiting {
 | 
|---|
| [62423350] | 108 |                         // use ordered data structure to maintain ordering for set_difference and for consistent error messages
 | 
|---|
 | 109 |                         typedef std::list< ObjectDecl * > ObjectSet;
 | 
|---|
| [698ec72] | 110 |                         void previsit( CompoundStmt *compoundStmt );
 | 
|---|
 | 111 |                         void previsit( DeclStmt *stmt );
 | 
|---|
| [52c14b3] | 112 | 
 | 
|---|
 | 113 |                         // don't go into other functions
 | 
|---|
| [698ec72] | 114 |                         void previsit( FunctionDecl * ) { visit_children = false; }
 | 
|---|
| [52c14b3] | 115 | 
 | 
|---|
| [c2931ea] | 116 |                   protected:
 | 
|---|
 | 117 |                         ObjectSet curVars;
 | 
|---|
 | 118 |                 };
 | 
|---|
 | 119 | 
 | 
|---|
| [6cf27a07] | 120 |                 // debug
 | 
|---|
| [62423350] | 121 |                 template<typename ObjectSet>
 | 
|---|
 | 122 |                 struct PrintSet {
 | 
|---|
 | 123 |                         PrintSet( const ObjectSet & objs ) : objs( objs ) {}
 | 
|---|
| [c2931ea] | 124 |                         const ObjectSet & objs;
 | 
|---|
 | 125 |                 };
 | 
|---|
| [62423350] | 126 |                 template<typename ObjectSet>
 | 
|---|
 | 127 |                 PrintSet<ObjectSet> printSet( const ObjectSet & objs ) { return PrintSet<ObjectSet>( objs ); }
 | 
|---|
 | 128 |                 template<typename ObjectSet>
 | 
|---|
 | 129 |                 std::ostream & operator<<( std::ostream & out, const PrintSet<ObjectSet> & set) {
 | 
|---|
| [c2931ea] | 130 |                         out << "{ ";
 | 
|---|
 | 131 |                         for ( ObjectDecl * obj : set.objs ) {
 | 
|---|
 | 132 |                                 out << obj->get_name() << ", " ;
 | 
|---|
| [adcc065] | 133 |                         } // for
 | 
|---|
| [c2931ea] | 134 |                         out << " }";
 | 
|---|
 | 135 |                         return out;
 | 
|---|
 | 136 |                 }
 | 
|---|
 | 137 | 
 | 
|---|
| [698ec72] | 138 |                 struct LabelFinder final : public ObjDeclCollector {
 | 
|---|
| [c2931ea] | 139 |                         typedef std::map< Label, ObjectSet > LabelMap;
 | 
|---|
 | 140 |                         // map of Label -> live variables at that label
 | 
|---|
 | 141 |                         LabelMap vars;
 | 
|---|
 | 142 | 
 | 
|---|
| [698ec72] | 143 |                         typedef ObjDeclCollector Parent;
 | 
|---|
 | 144 |                         using Parent::previsit;
 | 
|---|
 | 145 |                         void previsit( Statement * stmt );
 | 
|---|
 | 146 | 
 | 
|---|
 | 147 |                         void previsit( CompoundStmt *compoundStmt );
 | 
|---|
 | 148 |                         void previsit( DeclStmt *stmt );
 | 
|---|
| [c2931ea] | 149 |                 };
 | 
|---|
 | 150 | 
 | 
|---|
| [698ec72] | 151 |                 struct InsertDtors final : public ObjDeclCollector, public WithStmtsToAdd {
 | 
|---|
| [adcc065] | 152 |                         /// insert destructor calls at the appropriate places.  must happen before CtorInit nodes are removed
 | 
|---|
 | 153 |                         /// (currently by FixInit)
 | 
|---|
| [c2931ea] | 154 |                         static void insert( std::list< Declaration * > & translationUnit );
 | 
|---|
 | 155 | 
 | 
|---|
 | 156 |                         typedef std::list< ObjectDecl * > OrderedDecls;
 | 
|---|
 | 157 |                         typedef std::list< OrderedDecls > OrderedDeclsStack;
 | 
|---|
 | 158 | 
 | 
|---|
| [698ec72] | 159 |                         InsertDtors( PassVisitor<LabelFinder> & finder ) : finder( finder ), labelVars( finder.pass.vars ) {}
 | 
|---|
| [c2931ea] | 160 | 
 | 
|---|
| [698ec72] | 161 |                         typedef ObjDeclCollector Parent;
 | 
|---|
 | 162 |                         using Parent::previsit;
 | 
|---|
| [62e5546] | 163 | 
 | 
|---|
| [698ec72] | 164 |                         void previsit( ObjectDecl * objDecl );
 | 
|---|
 | 165 |                         void previsit( FunctionDecl * funcDecl );
 | 
|---|
| [c2931ea] | 166 | 
 | 
|---|
| [698ec72] | 167 |                         void previsit( CompoundStmt * compoundStmt );
 | 
|---|
 | 168 |                         void postvisit( CompoundStmt * compoundStmt );
 | 
|---|
 | 169 |                         void previsit( ReturnStmt * returnStmt );
 | 
|---|
 | 170 |                         void previsit( BranchStmt * stmt );
 | 
|---|
| [c2931ea] | 171 |                 private:
 | 
|---|
 | 172 |                         void handleGoto( BranchStmt * stmt );
 | 
|---|
 | 173 | 
 | 
|---|
| [698ec72] | 174 |                         PassVisitor<LabelFinder> & finder;
 | 
|---|
| [c2931ea] | 175 |                         LabelFinder::LabelMap & labelVars;
 | 
|---|
 | 176 |                         OrderedDeclsStack reverseDeclOrder;
 | 
|---|
 | 177 |                 };
 | 
|---|
 | 178 | 
 | 
|---|
| [0508ab3] | 179 |                 class FixInit : public WithStmtsToAdd {
 | 
|---|
| [c2931ea] | 180 |                   public:
 | 
|---|
 | 181 |                         /// expand each object declaration to use its constructor after it is declared.
 | 
|---|
 | 182 |                         static void fixInitializers( std::list< Declaration * > &translationUnit );
 | 
|---|
 | 183 | 
 | 
|---|
| [aff3af4] | 184 |                         DeclarationWithType * postmutate( ObjectDecl *objDecl );
 | 
|---|
| [72e9222] | 185 | 
 | 
|---|
 | 186 |                         std::list< Declaration * > staticDtorDecls;
 | 
|---|
| [c2931ea] | 187 |                 };
 | 
|---|
 | 188 | 
 | 
|---|
| [b8baa37] | 189 |                 class FixCopyCtors final : public WithStmtsToAdd, public WithShortCircuiting, public WithVisitorRef<FixCopyCtors>, public WithTypeSubstitution {
 | 
|---|
| [c2931ea] | 190 |                   public:
 | 
|---|
| [597db97f] | 191 |                         FixCopyCtors( UnqCount & unqCount ) : unqCount( unqCount ){}
 | 
|---|
| [adcc065] | 192 |                         /// expand ImplicitCopyCtorExpr nodes into the temporary declarations, copy constructors, call expression,
 | 
|---|
 | 193 |                         /// and destructors
 | 
|---|
| [597db97f] | 194 |                         static void fixCopyCtors( std::list< Declaration * > &translationUnit, UnqCount & unqCount );
 | 
|---|
| [c2931ea] | 195 | 
 | 
|---|
| [dc2334c] | 196 |                         Expression * postmutate( ImplicitCopyCtorExpr * impCpCtorExpr );
 | 
|---|
 | 197 |                         void premutate( StmtExpr * stmtExpr );
 | 
|---|
 | 198 |                         void premutate( UniqueExpr * unqExpr );
 | 
|---|
| [597db97f] | 199 | 
 | 
|---|
 | 200 |                         UnqCount & unqCount;
 | 
|---|
| [c2931ea] | 201 |                 };
 | 
|---|
| [79970ed] | 202 | 
 | 
|---|
| [b3fc977] | 203 |                 struct GenStructMemberCalls final : public WithGuards, public WithShortCircuiting, public WithIndexer, public WithVisitorRef<GenStructMemberCalls> {
 | 
|---|
| [c8dfcd3] | 204 |                         /// generate default/copy ctor and dtor calls for user-defined struct ctor/dtors
 | 
|---|
 | 205 |                         /// for any member that is missing a corresponding ctor/dtor call.
 | 
|---|
 | 206 |                         /// error if a member is used before constructed
 | 
|---|
 | 207 |                         static void generate( std::list< Declaration * > & translationUnit );
 | 
|---|
| [79970ed] | 208 | 
 | 
|---|
| [b3fc977] | 209 |                         void premutate( FunctionDecl * funcDecl );
 | 
|---|
 | 210 |                         DeclarationWithType * postmutate( FunctionDecl * funcDecl );
 | 
|---|
 | 211 | 
 | 
|---|
 | 212 |                         void premutate( MemberExpr * memberExpr );
 | 
|---|
 | 213 |                         void premutate( ApplicationExpr * appExpr );
 | 
|---|
| [79970ed] | 214 | 
 | 
|---|
| [b3fc977] | 215 |                         /// Note: this post mutate used to be in a separate visitor. If this pass breaks, one place to examine is whether it is
 | 
|---|
 | 216 |                         /// okay for this part of the recursion to occur alongside the rest.
 | 
|---|
 | 217 |                         Expression * postmutate( UntypedExpr * expr );
 | 
|---|
| [79970ed] | 218 | 
 | 
|---|
| [a16764a6] | 219 |                         SemanticErrorException errors;
 | 
|---|
| [79970ed] | 220 |                   private:
 | 
|---|
| [3906301] | 221 |                         template< typename... Params >
 | 
|---|
| [64ac636] | 222 |                         void emit( CodeLocation, const Params &... params );
 | 
|---|
| [79970ed] | 223 | 
 | 
|---|
| [5363fdf] | 224 |                         FunctionDecl * function = nullptr;
 | 
|---|
| [64ac636] | 225 |                         std::set< DeclarationWithType * > unhandled;
 | 
|---|
 | 226 |                         std::map< DeclarationWithType *, CodeLocation > usedUninit;
 | 
|---|
| [5363fdf] | 227 |                         ObjectDecl * thisParam = nullptr;
 | 
|---|
| [c8dfcd3] | 228 |                         bool isCtor = false; // true if current function is a constructor
 | 
|---|
| [5363fdf] | 229 |                         StructDecl * structDecl = nullptr;
 | 
|---|
| [c8dfcd3] | 230 |                 };
 | 
|---|
 | 231 | 
 | 
|---|
| [696bf6e] | 232 |                 struct FixCtorExprs final : public WithDeclsToAdd, public WithIndexer {
 | 
|---|
| [b6fe7e6] | 233 |                         /// expands ConstructorExpr nodes into comma expressions, using a temporary for the first argument
 | 
|---|
 | 234 |                         static void fix( std::list< Declaration * > & translationUnit );
 | 
|---|
 | 235 | 
 | 
|---|
| [696bf6e] | 236 |                         Expression * postmutate( ConstructorExpr * ctorExpr );
 | 
|---|
| [b6fe7e6] | 237 |                 };
 | 
|---|
| [c2931ea] | 238 |         } // namespace
 | 
|---|
| [db4ecc5] | 239 | 
 | 
|---|
| [6cf27a07] | 240 |         void fix( std::list< Declaration * > & translationUnit, const std::string & filename, bool inLibrary ) {
 | 
|---|
| [babeeda] | 241 |                 PassVisitor<SelfAssignChecker> checker;
 | 
|---|
 | 242 |                 acceptAll( translationUnit, checker );
 | 
|---|
 | 243 | 
 | 
|---|
| [6cf27a07] | 244 |                 // fixes ConstructorInit for global variables. should happen before fixInitializers.
 | 
|---|
 | 245 |                 InitTweak::fixGlobalInit( translationUnit, filename, inLibrary );
 | 
|---|
 | 246 | 
 | 
|---|
| [597db97f] | 247 |                 UnqCount unqCount;
 | 
|---|
| [b6fe7e6] | 248 | 
 | 
|---|
| [c0714bf] | 249 |                 InsertImplicitCalls::insert( translationUnit );
 | 
|---|
 | 250 |                 ResolveCopyCtors::resolveImplicitCalls( translationUnit, unqCount );
 | 
|---|
| [c2931ea] | 251 |                 InsertDtors::insert( translationUnit );
 | 
|---|
| [71f4e4f] | 252 |                 FixInit::fixInitializers( translationUnit );
 | 
|---|
| [c2931ea] | 253 | 
 | 
|---|
| [db4ecc5] | 254 |                 // FixCopyCtors must happen after FixInit, so that destructors are placed correctly
 | 
|---|
| [597db97f] | 255 |                 FixCopyCtors::fixCopyCtors( translationUnit, unqCount );
 | 
|---|
| [79970ed] | 256 | 
 | 
|---|
| [c8dfcd3] | 257 |                 GenStructMemberCalls::generate( translationUnit );
 | 
|---|
| [ae1b9ea] | 258 | 
 | 
|---|
| [b6fe7e6] | 259 |                 // xxx - ctor expansion currently has to be after FixCopyCtors, because there is currently a
 | 
|---|
 | 260 |                 // hack in the way untyped assignments are generated, where the first argument cannot have
 | 
|---|
 | 261 |                 // its address taken because of the way codegeneration handles UntypedExpr vs. ApplicationExpr.
 | 
|---|
 | 262 |                 // Thus such assignment exprs must never pushed through expression resolution (and thus should
 | 
|---|
 | 263 |                 // not go through the FixCopyCtors pass), otherwise they will fail -- guaranteed.
 | 
|---|
 | 264 |                 // Also needs to happen after GenStructMemberCalls, since otherwise member constructors exprs
 | 
|---|
 | 265 |                 // don't look right, and a member can be constructed more than once.
 | 
|---|
 | 266 |                 FixCtorExprs::fix( translationUnit );
 | 
|---|
| [db4ecc5] | 267 |         }
 | 
|---|
 | 268 | 
 | 
|---|
| [c2931ea] | 269 |         namespace {
 | 
|---|
| [c0714bf] | 270 |                 void InsertImplicitCalls::insert( std::list< Declaration * > & translationUnit ) {
 | 
|---|
 | 271 |                         PassVisitor<InsertImplicitCalls> inserter;
 | 
|---|
| [c2931ea] | 272 |                         mutateAll( translationUnit, inserter );
 | 
|---|
 | 273 |                 }
 | 
|---|
| [db4ecc5] | 274 | 
 | 
|---|
| [c0714bf] | 275 |                 void ResolveCopyCtors::resolveImplicitCalls( std::list< Declaration * > & translationUnit, UnqCount & unqCount ) {
 | 
|---|
 | 276 |                         PassVisitor<ResolveCopyCtors> resolver( unqCount );
 | 
|---|
| [c2931ea] | 277 |                         acceptAll( translationUnit, resolver );
 | 
|---|
 | 278 |                 }
 | 
|---|
| [71f4e4f] | 279 | 
 | 
|---|
| [c2931ea] | 280 |                 void FixInit::fixInitializers( std::list< Declaration * > & translationUnit ) {
 | 
|---|
| [aff3af4] | 281 |                         PassVisitor<FixInit> fixer;
 | 
|---|
| [72e9222] | 282 | 
 | 
|---|
 | 283 |                         // can't use mutateAll, because need to insert declarations at top-level
 | 
|---|
 | 284 |                         // can't use DeclMutator, because sometimes need to insert IfStmt, etc.
 | 
|---|
| [a16764a6] | 285 |                         SemanticErrorException errors;
 | 
|---|
| [72e9222] | 286 |                         for ( std::list< Declaration * >::iterator i = translationUnit.begin(); i != translationUnit.end(); ++i ) {
 | 
|---|
 | 287 |                                 try {
 | 
|---|
| [3c398b6] | 288 |                                         maybeMutate( *i, fixer );
 | 
|---|
| [aff3af4] | 289 |                                         translationUnit.splice( i, fixer.pass.staticDtorDecls );
 | 
|---|
| [a16764a6] | 290 |                                 } catch( SemanticErrorException &e ) {
 | 
|---|
| [72e9222] | 291 |                                         errors.append( e );
 | 
|---|
 | 292 |                                 } // try
 | 
|---|
 | 293 |                         } // for
 | 
|---|
 | 294 |                         if ( ! errors.isEmpty() ) {
 | 
|---|
 | 295 |                                 throw errors;
 | 
|---|
 | 296 |                         } // if
 | 
|---|
| [c2931ea] | 297 |                 }
 | 
|---|
| [71f4e4f] | 298 | 
 | 
|---|
| [c2931ea] | 299 |                 void InsertDtors::insert( std::list< Declaration * > & translationUnit ) {
 | 
|---|
| [698ec72] | 300 |                         PassVisitor<LabelFinder> finder;
 | 
|---|
 | 301 |                         PassVisitor<InsertDtors> inserter( finder );
 | 
|---|
| [c2931ea] | 302 |                         acceptAll( translationUnit, inserter );
 | 
|---|
 | 303 |                 }
 | 
|---|
 | 304 | 
 | 
|---|
| [597db97f] | 305 |                 void FixCopyCtors::fixCopyCtors( std::list< Declaration * > & translationUnit, UnqCount & unqCount ) {
 | 
|---|
| [dc2334c] | 306 |                         PassVisitor<FixCopyCtors> fixer( unqCount );
 | 
|---|
| [c2931ea] | 307 |                         mutateAll( translationUnit, fixer );
 | 
|---|
 | 308 |                 }
 | 
|---|
| [db4ecc5] | 309 | 
 | 
|---|
| [c8dfcd3] | 310 |                 void GenStructMemberCalls::generate( std::list< Declaration * > & translationUnit ) {
 | 
|---|
| [9a707e4e] | 311 |                         PassVisitor<GenStructMemberCalls> warner;
 | 
|---|
| [b3fc977] | 312 |                         mutateAll( translationUnit, warner );
 | 
|---|
| [79970ed] | 313 |                 }
 | 
|---|
 | 314 | 
 | 
|---|
| [b6fe7e6] | 315 |                 void FixCtorExprs::fix( std::list< Declaration * > & translationUnit ) {
 | 
|---|
| [696bf6e] | 316 |                         PassVisitor<FixCtorExprs> fixer;
 | 
|---|
 | 317 |                         mutateAll( translationUnit, fixer );
 | 
|---|
| [b6fe7e6] | 318 |                 }
 | 
|---|
 | 319 | 
 | 
|---|
| [babeeda] | 320 |                 namespace {
 | 
|---|
 | 321 |                         // Relatively simple structural comparison for expressions, needed to determine
 | 
|---|
 | 322 |                         // if two expressions are "the same" (used to determine if self assignment occurs)
 | 
|---|
 | 323 |                         struct StructuralChecker {
 | 
|---|
 | 324 |                                 Expression * stripCasts( Expression * expr ) {
 | 
|---|
 | 325 |                                         // this might be too permissive. It's possible that only particular casts are relevant.
 | 
|---|
 | 326 |                                         while ( CastExpr * cast = dynamic_cast< CastExpr * >( expr ) ) {
 | 
|---|
 | 327 |                                                 expr = cast->arg;
 | 
|---|
 | 328 |                                         }
 | 
|---|
 | 329 |                                         return expr;
 | 
|---|
 | 330 |                                 }
 | 
|---|
 | 331 | 
 | 
|---|
 | 332 |                                 void previsit( Expression * ) {
 | 
|---|
 | 333 |                                         // anything else does not qualify
 | 
|---|
 | 334 |                                         isSimilar = false;
 | 
|---|
 | 335 |                                 }
 | 
|---|
 | 336 | 
 | 
|---|
 | 337 |                                 template<typename T>
 | 
|---|
 | 338 |                                 T * cast( Expression * node ) {
 | 
|---|
 | 339 |                                         // all expressions need to ignore casts, so this bit has been factored out
 | 
|---|
 | 340 |                                         return dynamic_cast< T * >( stripCasts( node ) );
 | 
|---|
 | 341 |                                 }
 | 
|---|
 | 342 | 
 | 
|---|
 | 343 |                                 // ignore casts
 | 
|---|
 | 344 |                                 void previsit( CastExpr * ) {}
 | 
|---|
 | 345 | 
 | 
|---|
 | 346 |                                 void previsit( MemberExpr * memExpr ) {
 | 
|---|
 | 347 |                                         if ( MemberExpr * otherMember = cast< MemberExpr >( other ) ) {
 | 
|---|
 | 348 |                                                 if ( otherMember->member == memExpr->member ) {
 | 
|---|
 | 349 |                                                         other = otherMember->aggregate;
 | 
|---|
 | 350 |                                                         return;
 | 
|---|
 | 351 |                                                 }
 | 
|---|
 | 352 |                                         }
 | 
|---|
 | 353 |                                         isSimilar = false;
 | 
|---|
 | 354 |                                 }
 | 
|---|
 | 355 | 
 | 
|---|
 | 356 |                                 void previsit( VariableExpr * varExpr ) {
 | 
|---|
 | 357 |                                         if ( VariableExpr * otherVar = cast< VariableExpr >( other ) ) {
 | 
|---|
 | 358 |                                                 if ( otherVar->var == varExpr->var ) {
 | 
|---|
 | 359 |                                                         return;
 | 
|---|
 | 360 |                                                 }
 | 
|---|
 | 361 |                                         }
 | 
|---|
 | 362 |                                         isSimilar = false;
 | 
|---|
 | 363 |                                 }
 | 
|---|
 | 364 | 
 | 
|---|
 | 365 |                                 void previsit( AddressExpr * ) {
 | 
|---|
 | 366 |                                         if ( AddressExpr * addrExpr = cast< AddressExpr >( other ) ) {
 | 
|---|
 | 367 |                                                 other = addrExpr->arg;
 | 
|---|
 | 368 |                                                 return;
 | 
|---|
 | 369 |                                         }
 | 
|---|
 | 370 |                                         isSimilar = false;
 | 
|---|
 | 371 |                                 }
 | 
|---|
 | 372 | 
 | 
|---|
 | 373 |                                 Expression * other = nullptr;
 | 
|---|
 | 374 |                                 bool isSimilar = true;
 | 
|---|
 | 375 |                         };
 | 
|---|
 | 376 | 
 | 
|---|
 | 377 |                         bool structurallySimilar( Expression * e1, Expression * e2 ) {
 | 
|---|
 | 378 |                                 PassVisitor<StructuralChecker> checker;
 | 
|---|
 | 379 |                                 checker.pass.other = e2;
 | 
|---|
 | 380 |                                 e1->accept( checker );
 | 
|---|
 | 381 |                                 return checker.pass.isSimilar;
 | 
|---|
 | 382 |                         }
 | 
|---|
 | 383 |                 }
 | 
|---|
 | 384 | 
 | 
|---|
 | 385 |                 void SelfAssignChecker::previsit( ApplicationExpr * appExpr ) {
 | 
|---|
 | 386 |                         DeclarationWithType * function = getFunction( appExpr );
 | 
|---|
| [a0c7d5cc] | 387 |                         if ( function->name == "?=?" ) { // doesn't use isAssignment, because ?+=?, etc. should not count as self-assignment
 | 
|---|
| [babeeda] | 388 |                                 if ( appExpr->args.size() == 2 ) {
 | 
|---|
 | 389 |                                         // check for structural similarity (same variable use, ignore casts, etc. - but does not look too deeply, anything looking like a function is off limits)
 | 
|---|
 | 390 |                                         if ( structurallySimilar( appExpr->args.front(), appExpr->args.back() ) ) {
 | 
|---|
 | 391 |                                                 SemanticWarning( appExpr->location, Warning::SelfAssignment, toCString( appExpr->args.front() ) );
 | 
|---|
 | 392 |                                         }
 | 
|---|
 | 393 |                                 }
 | 
|---|
 | 394 |                         }
 | 
|---|
 | 395 |                 }
 | 
|---|
 | 396 | 
 | 
|---|
| [134322e] | 397 |                 Expression * InsertImplicitCalls::postmutate( ApplicationExpr * appExpr ) {
 | 
|---|
| [c2931ea] | 398 |                         if ( VariableExpr * function = dynamic_cast< VariableExpr * > ( appExpr->get_function() ) ) {
 | 
|---|
| [be151bf] | 399 |                                 if ( function->var->linkage.is_builtin ) {
 | 
|---|
| [c2931ea] | 400 |                                         // optimization: don't need to copy construct in order to call intrinsic functions
 | 
|---|
 | 401 |                                         return appExpr;
 | 
|---|
 | 402 |                                 } else if ( DeclarationWithType * funcDecl = dynamic_cast< DeclarationWithType * > ( function->get_var() ) ) {
 | 
|---|
 | 403 |                                         FunctionType * ftype = dynamic_cast< FunctionType * >( GenPoly::getFunctionType( funcDecl->get_type() ) );
 | 
|---|
| [05807e9] | 404 |                                         assertf( ftype, "Function call without function type: %s", toString( funcDecl ).c_str() );
 | 
|---|
| [be151bf] | 405 |                                         if ( CodeGen::isConstructor( funcDecl->get_name() ) && ftype->parameters.size() == 2 ) {
 | 
|---|
 | 406 |                                                 Type * t1 = getPointerBase( ftype->parameters.front()->get_type() );
 | 
|---|
 | 407 |                                                 Type * t2 = ftype->parameters.back()->get_type();
 | 
|---|
| [0a81c3f] | 408 |                                                 assert( t1 );
 | 
|---|
| [c2931ea] | 409 | 
 | 
|---|
| [0a81c3f] | 410 |                                                 if ( ResolvExpr::typesCompatible( t1, t2, SymTab::Indexer() ) ) {
 | 
|---|
| [a28bc02] | 411 |                                                         // optimization: don't need to copy construct in order to call a copy constructor
 | 
|---|
| [c2931ea] | 412 |                                                         return appExpr;
 | 
|---|
| [adcc065] | 413 |                                                 } // if
 | 
|---|
| [bff227f] | 414 |                                         } else if ( CodeGen::isDestructor( funcDecl->get_name() ) ) {
 | 
|---|
| [c2931ea] | 415 |                                                 // correctness: never copy construct arguments to a destructor
 | 
|---|
| [845cedc] | 416 |                                                 return appExpr;
 | 
|---|
| [adcc065] | 417 |                                         } // if
 | 
|---|
 | 418 |                                 } // if
 | 
|---|
 | 419 |                         } // if
 | 
|---|
| [c2931ea] | 420 |                         CP_CTOR_PRINT( std::cerr << "InsertImplicitCalls: adding a wrapper " << appExpr << std::endl; )
 | 
|---|
 | 421 | 
 | 
|---|
 | 422 |                         // wrap each function call so that it is easy to identify nodes that have to be copy constructed
 | 
|---|
 | 423 |                         ImplicitCopyCtorExpr * expr = new ImplicitCopyCtorExpr( appExpr );
 | 
|---|
| [c0714bf] | 424 |                         // Move the type substitution to the new top-level, if it is attached to the appExpr.
 | 
|---|
| [c2931ea] | 425 |                         // Ensure it is not deleted with the ImplicitCopyCtorExpr by removing it before deletion.
 | 
|---|
 | 426 |                         // The substitution is needed to obtain the type of temporary variables so that copy constructor
 | 
|---|
| [c0714bf] | 427 |                         // calls can be resolved.
 | 
|---|
| [c2931ea] | 428 |                         assert( env );
 | 
|---|
| [c0714bf] | 429 |                         std::swap( expr->env, appExpr->env );
 | 
|---|
| [c2931ea] | 430 |                         return expr;
 | 
|---|
| [db4ecc5] | 431 |                 }
 | 
|---|
 | 432 | 
 | 
|---|
| [29bc63e] | 433 |                 bool ResolveCopyCtors::skipCopyConstruct( Type * type ) { return ! isConstructable( type ); }
 | 
|---|
| [c2931ea] | 434 | 
 | 
|---|
| [65660bd] | 435 |                 Expression * ResolveCopyCtors::makeCtorDtor( const std::string & fname, ObjectDecl * var, Expression * cpArg ) {
 | 
|---|
| [c2931ea] | 436 |                         assert( var );
 | 
|---|
| [092528b] | 437 |                         // arrays are not copy constructed, so this should always be an ExprStmt
 | 
|---|
 | 438 |                         ImplicitCtorDtorStmt * stmt = genCtorDtor( fname, var, cpArg );
 | 
|---|
| [9fe33947] | 439 |                         assertf( stmt, "ResolveCopyCtors: genCtorDtor returned nullptr: %s / %s / %s", fname.c_str(), toString( var ).c_str(), toString( cpArg ).c_str() );
 | 
|---|
 | 440 |                         ExprStmt * exprStmt = strict_dynamic_cast< ExprStmt * >( stmt->callStmt );
 | 
|---|
| [08da53d] | 441 |                         Expression * resolved = exprStmt->expr;
 | 
|---|
 | 442 |                         exprStmt->expr = nullptr; // take ownership of expr
 | 
|---|
| [c2931ea] | 443 | 
 | 
|---|
 | 444 |                         // resolve copy constructor
 | 
|---|
| [adcc065] | 445 |                         // should only be one alternative for copy ctor and dtor expressions, since all arguments are fixed
 | 
|---|
 | 446 |                         // (VariableExpr and already resolved expression)
 | 
|---|
| [08da53d] | 447 |                         CP_CTOR_PRINT( std::cerr << "ResolvingCtorDtor " << resolved << std::endl; )
 | 
|---|
 | 448 |                         ResolvExpr::findVoidExpression( resolved, indexer );
 | 
|---|
| [65660bd] | 449 |                         assert( resolved );
 | 
|---|
| [dd05e12] | 450 |                         if ( resolved->env ) {
 | 
|---|
| [31f379c] | 451 |                                 // Extract useful information and discard new environments. Keeping them causes problems in PolyMutator passes.
 | 
|---|
| [dd05e12] | 452 |                                 env->add( *resolved->env );
 | 
|---|
 | 453 |                                 delete resolved->env;
 | 
|---|
 | 454 |                                 resolved->env = nullptr;
 | 
|---|
| [adcc065] | 455 |                         } // if
 | 
|---|
| [092528b] | 456 |                         delete stmt;
 | 
|---|
| [7641b6c] | 457 |                         if ( TupleAssignExpr * assign = dynamic_cast< TupleAssignExpr * >( resolved ) ) {
 | 
|---|
 | 458 |                                 // fix newly generated StmtExpr
 | 
|---|
 | 459 |                                 postvisit( assign->stmtExpr );
 | 
|---|
 | 460 |                         }
 | 
|---|
| [c2931ea] | 461 |                         return resolved;
 | 
|---|
| [540de412] | 462 |                 }
 | 
|---|
| [db4ecc5] | 463 | 
 | 
|---|
| [ae1b9ea] | 464 |                 void ResolveCopyCtors::copyConstructArg( Expression *& arg, ImplicitCopyCtorExpr * impCpCtorExpr, Type * formal ) {
 | 
|---|
| [c2931ea] | 465 |                         static UniqueName tempNamer("_tmp_cp");
 | 
|---|
| [31f379c] | 466 |                         assert( env );
 | 
|---|
 | 467 |                         CP_CTOR_PRINT( std::cerr << "Type Substitution: " << *env << std::endl; )
 | 
|---|
| [d29fa5f] | 468 |                         assert( arg->result );
 | 
|---|
| [ae1b9ea] | 469 |                         Type * result = arg->result;
 | 
|---|
| [1132b62] | 470 |                         if ( skipCopyConstruct( result ) ) return; // skip certain non-copyable types
 | 
|---|
 | 471 | 
 | 
|---|
| [f5c3b6c] | 472 |                         // type may involve type variables, so apply type substitution to get temporary variable's actual type,
 | 
|---|
 | 473 |                         // since result type may not be substituted (e.g., if the type does not appear in the parameter list)
 | 
|---|
| [ae1b9ea] | 474 |                         // Use applyFree so that types bound in function pointers are not substituted, e.g. in forall(dtype T) void (*)(T).
 | 
|---|
 | 475 |                         env->applyFree( result );
 | 
|---|
| [3aeaecd] | 476 |                         ObjectDecl * tmp = ObjectDecl::newObject( "__tmp", result, nullptr );
 | 
|---|
| [615a096] | 477 |                         tmp->get_type()->set_const( false );
 | 
|---|
| [1132b62] | 478 | 
 | 
|---|
 | 479 |                         // create and resolve copy constructor
 | 
|---|
 | 480 |                         CP_CTOR_PRINT( std::cerr << "makeCtorDtor for an argument" << std::endl; )
 | 
|---|
| [65660bd] | 481 |                         Expression * cpCtor = makeCtorDtor( "?{}", tmp, arg );
 | 
|---|
 | 482 | 
 | 
|---|
 | 483 |                         if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( cpCtor ) ) {
 | 
|---|
 | 484 |                                 // if the chosen constructor is intrinsic, the copy is unnecessary, so
 | 
|---|
 | 485 |                                 // don't create the temporary and don't call the copy constructor
 | 
|---|
| [ae1b9ea] | 486 |                                 VariableExpr * function = strict_dynamic_cast< VariableExpr * >( appExpr->function );
 | 
|---|
 | 487 |                                 if ( function->var->linkage == LinkageSpec::Intrinsic ) {
 | 
|---|
 | 488 |                                         // arguments that need to be boxed need a temporary regardless of whether the copy constructor is intrinsic,
 | 
|---|
 | 489 |                                         // so that the object isn't changed inside of the polymorphic function
 | 
|---|
 | 490 |                                         if ( ! GenPoly::needsBoxing( formal, result, impCpCtorExpr->callExpr, env ) ) return;
 | 
|---|
 | 491 |                                 }
 | 
|---|
| [65660bd] | 492 |                         }
 | 
|---|
 | 493 | 
 | 
|---|
| [3aeaecd] | 494 |                         // set a unique name for the temporary once it's certain the call is necessary
 | 
|---|
 | 495 |                         tmp->name = tempNamer.newName();
 | 
|---|
 | 496 | 
 | 
|---|
| [65660bd] | 497 |                         // replace argument to function call with temporary
 | 
|---|
 | 498 |                         arg = new CommaExpr( cpCtor, new VariableExpr( tmp ) );
 | 
|---|
| [ae1b9ea] | 499 |                         impCpCtorExpr->tempDecls.push_back( tmp );
 | 
|---|
 | 500 |                         impCpCtorExpr->dtors.push_front( makeCtorDtor( "^?{}", tmp ) );
 | 
|---|
| [1132b62] | 501 |                 }
 | 
|---|
| [c2931ea] | 502 | 
 | 
|---|
| [092528b] | 503 |                 void ResolveCopyCtors::destructRet( ObjectDecl * ret, ImplicitCopyCtorExpr * impCpCtorExpr ) {
 | 
|---|
 | 504 |                         impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) );
 | 
|---|
| [1132b62] | 505 |                 }
 | 
|---|
 | 506 | 
 | 
|---|
| [c0714bf] | 507 |                 void ResolveCopyCtors::postvisit( ImplicitCopyCtorExpr *impCpCtorExpr ) {
 | 
|---|
| [c2931ea] | 508 |                         CP_CTOR_PRINT( std::cerr << "ResolveCopyCtors: " << impCpCtorExpr << std::endl; )
 | 
|---|
 | 509 | 
 | 
|---|
| [ae1b9ea] | 510 |                         ApplicationExpr * appExpr = impCpCtorExpr->callExpr;
 | 
|---|
| [c2931ea] | 511 | 
 | 
|---|
 | 512 |                         // take each argument and attempt to copy construct it.
 | 
|---|
| [ae1b9ea] | 513 |                         FunctionType * ftype = GenPoly::getFunctionType( appExpr->function->result );
 | 
|---|
 | 514 |                         assert( ftype );
 | 
|---|
 | 515 |                         auto & params = ftype->parameters;
 | 
|---|
 | 516 |                         auto iter = params.begin();
 | 
|---|
 | 517 |                         for ( Expression * & arg : appExpr->args ) {
 | 
|---|
 | 518 |                                 Type * formal = nullptr;
 | 
|---|
 | 519 |                                 if ( iter != params.end() ) {
 | 
|---|
 | 520 |                                         DeclarationWithType * param = *iter++;
 | 
|---|
 | 521 |                                         formal = param->get_type();
 | 
|---|
 | 522 |                                 }
 | 
|---|
 | 523 | 
 | 
|---|
 | 524 |                                 copyConstructArg( arg, impCpCtorExpr, formal );
 | 
|---|
| [adcc065] | 525 |                         } // for
 | 
|---|
| [db4ecc5] | 526 | 
 | 
|---|
| [adcc065] | 527 |                         // each return value from the call needs to be connected with an ObjectDecl at the call site, which is
 | 
|---|
 | 528 |                         // initialized with the return value and is destructed later
 | 
|---|
| [31f379c] | 529 |                         // xxx - handle named return values?
 | 
|---|
| [ae1b9ea] | 530 |                         Type * result = appExpr->result;
 | 
|---|
| [906e24d] | 531 |                         if ( ! result->isVoid() ) {
 | 
|---|
| [1132b62] | 532 |                                 static UniqueName retNamer("_tmp_cp_ret");
 | 
|---|
| [c2931ea] | 533 |                                 result = result->clone();
 | 
|---|
| [31f379c] | 534 |                                 env->apply( result );
 | 
|---|
| [3aeaecd] | 535 |                                 ObjectDecl * ret = ObjectDecl::newObject( retNamer.newName(), result, nullptr );
 | 
|---|
| [ae1b9ea] | 536 |                                 ret->type->set_const( false );
 | 
|---|
 | 537 |                                 impCpCtorExpr->returnDecls.push_back( ret );
 | 
|---|
| [c2931ea] | 538 |                                 CP_CTOR_PRINT( std::cerr << "makeCtorDtor for a return" << std::endl; )
 | 
|---|
| [0a81c3f] | 539 |                                 if ( ! dynamic_cast< ReferenceType * >( result ) ) {
 | 
|---|
| [3aeaecd] | 540 |                                         // destructing reference returns is bad because it can cause multiple destructor calls to the same object - the returned object is not a temporary
 | 
|---|
| [092528b] | 541 |                                         destructRet( ret, impCpCtorExpr );
 | 
|---|
| [dc86541] | 542 |                                 }
 | 
|---|
| [adcc065] | 543 |                         } // for
 | 
|---|
| [c2931ea] | 544 |                         CP_CTOR_PRINT( std::cerr << "after Resolving: " << impCpCtorExpr << std::endl; )
 | 
|---|
| [db4ecc5] | 545 |                 }
 | 
|---|
 | 546 | 
 | 
|---|
| [c0714bf] | 547 |                 void ResolveCopyCtors::postvisit( StmtExpr * stmtExpr ) {
 | 
|---|
 | 548 |                         assert( env );
 | 
|---|
| [31f379c] | 549 |                         assert( stmtExpr->get_result() );
 | 
|---|
 | 550 |                         Type * result = stmtExpr->get_result();
 | 
|---|
 | 551 |                         if ( ! result->isVoid() ) {
 | 
|---|
 | 552 |                                 static UniqueName retNamer("_tmp_stmtexpr_ret");
 | 
|---|
 | 553 | 
 | 
|---|
 | 554 |                                 result = result->clone();
 | 
|---|
 | 555 |                                 env->apply( result );
 | 
|---|
| [6dfa2e1] | 556 |                                 if ( ! InitTweak::isConstructable( result ) ) {
 | 
|---|
 | 557 |                                         delete result;
 | 
|---|
 | 558 |                                         return;
 | 
|---|
 | 559 |                                 }
 | 
|---|
 | 560 | 
 | 
|---|
 | 561 |                                 // create variable that will hold the result of the stmt expr
 | 
|---|
| [3aeaecd] | 562 |                                 ObjectDecl * ret = ObjectDecl::newObject( retNamer.newName(), result, nullptr );
 | 
|---|
| [7641b6c] | 563 |                                 ret->type->set_const( false );
 | 
|---|
 | 564 |                                 stmtExpr->returnDecls.push_front( ret );
 | 
|---|
| [31f379c] | 565 | 
 | 
|---|
 | 566 |                                 // must have a non-empty body, otherwise it wouldn't have a result
 | 
|---|
| [7641b6c] | 567 |                                 CompoundStmt * body = stmtExpr->statements;
 | 
|---|
| [31f379c] | 568 |                                 assert( ! body->get_kids().empty() );
 | 
|---|
 | 569 |                                 // must be an ExprStmt, otherwise it wouldn't have a result
 | 
|---|
| [e3e16bc] | 570 |                                 ExprStmt * last = strict_dynamic_cast< ExprStmt * >( body->get_kids().back() );
 | 
|---|
| [7641b6c] | 571 |                                 last->expr = makeCtorDtor( "?{}", ret, last->get_expr() );
 | 
|---|
| [31f379c] | 572 | 
 | 
|---|
| [7641b6c] | 573 |                                 stmtExpr->dtors.push_front( makeCtorDtor( "^?{}", ret ) );
 | 
|---|
| [31f379c] | 574 |                         } // if
 | 
|---|
 | 575 |                 }
 | 
|---|
 | 576 | 
 | 
|---|
| [c0714bf] | 577 |                 void ResolveCopyCtors::previsit( UniqueExpr * unqExpr ) {
 | 
|---|
| [597db97f] | 578 |                         unqCount[ unqExpr->get_id() ]++;  // count the number of unique expressions for each ID
 | 
|---|
| [c0714bf] | 579 |                         if ( vars.count( unqExpr->get_id() ) ) {
 | 
|---|
 | 580 |                                 // xxx - hack to prevent double-handling of unique exprs, otherwise too many temporary variables and destructors are generated
 | 
|---|
 | 581 |                                 visit_children = false;
 | 
|---|
 | 582 |                         }
 | 
|---|
 | 583 |                 }
 | 
|---|
 | 584 | 
 | 
|---|
| [ddae809] | 585 |                 // to prevent warnings (‘_unq0’ may be used uninitialized in this function),
 | 
|---|
 | 586 |                 // insert an appropriate zero initializer for UniqueExpr temporaries.
 | 
|---|
 | 587 |                 Initializer * makeInit( Type * t ) {
 | 
|---|
 | 588 |                         if ( StructInstType * inst = dynamic_cast< StructInstType * >( t ) ) {
 | 
|---|
 | 589 |                                 // initizer for empty struct must be empty
 | 
|---|
 | 590 |                                 if ( inst->baseStruct->members.empty() ) return new ListInit({});
 | 
|---|
 | 591 |                         } else if ( UnionInstType * inst = dynamic_cast< UnionInstType * >( t ) ) {
 | 
|---|
 | 592 |                                 // initizer for empty union must be empty
 | 
|---|
 | 593 |                                 if ( inst->baseUnion->members.empty() ) return new ListInit({});
 | 
|---|
 | 594 |                         }
 | 
|---|
 | 595 | 
 | 
|---|
 | 596 |                         return new ListInit( { new SingleInit( new ConstantExpr( Constant::from_int( 0 ) ) ) } );
 | 
|---|
 | 597 |                 }
 | 
|---|
 | 598 | 
 | 
|---|
| [c0714bf] | 599 |                 void ResolveCopyCtors::postvisit( UniqueExpr * unqExpr ) {
 | 
|---|
| [141b786] | 600 |                         if ( vars.count( unqExpr->get_id() ) ) {
 | 
|---|
 | 601 |                                 // xxx - hack to prevent double-handling of unique exprs, otherwise too many temporary variables and destructors are generated
 | 
|---|
 | 602 |                                 return;
 | 
|---|
 | 603 |                         }
 | 
|---|
 | 604 | 
 | 
|---|
 | 605 |                         // it should never be necessary to wrap a void-returning expression in a UniqueExpr - if this assumption changes, this needs to be rethought
 | 
|---|
 | 606 |                         assert( unqExpr->get_result() );
 | 
|---|
 | 607 |                         if ( ImplicitCopyCtorExpr * impCpCtorExpr = dynamic_cast<ImplicitCopyCtorExpr*>( unqExpr->get_expr() ) ) {
 | 
|---|
 | 608 |                                 // note the variable used as the result from the call
 | 
|---|
 | 609 |                                 assert( impCpCtorExpr->get_result() && impCpCtorExpr->get_returnDecls().size() == 1 );
 | 
|---|
 | 610 |                                 unqExpr->set_var( new VariableExpr( impCpCtorExpr->get_returnDecls().front() ) );
 | 
|---|
 | 611 |                         } else {
 | 
|---|
 | 612 |                                 // expr isn't a call expr, so create a new temporary variable to use to hold the value of the unique expression
 | 
|---|
| [ddae809] | 613 |                                 unqExpr->set_object( ObjectDecl::newObject( toString("_unq", unqExpr->get_id()), unqExpr->get_result()->clone(), makeInit( unqExpr->get_result() ) ) );
 | 
|---|
| [141b786] | 614 |                                 unqExpr->set_var( new VariableExpr( unqExpr->get_object() ) );
 | 
|---|
 | 615 |                         }
 | 
|---|
 | 616 |                         vars.insert( unqExpr->get_id() );
 | 
|---|
 | 617 |                 }
 | 
|---|
 | 618 | 
 | 
|---|
| [dc2334c] | 619 |                 Expression * FixCopyCtors::postmutate( ImplicitCopyCtorExpr * impCpCtorExpr ) {
 | 
|---|
| [c2931ea] | 620 |                         CP_CTOR_PRINT( std::cerr << "FixCopyCtors: " << impCpCtorExpr << std::endl; )
 | 
|---|
 | 621 | 
 | 
|---|
 | 622 |                         std::list< ObjectDecl * > & tempDecls = impCpCtorExpr->get_tempDecls();
 | 
|---|
 | 623 |                         std::list< ObjectDecl * > & returnDecls = impCpCtorExpr->get_returnDecls();
 | 
|---|
 | 624 |                         std::list< Expression * > & dtors = impCpCtorExpr->get_dtors();
 | 
|---|
| [845cedc] | 625 | 
 | 
|---|
| [c2931ea] | 626 |                         // add all temporary declarations and their constructors
 | 
|---|
 | 627 |                         for ( ObjectDecl * obj : tempDecls ) {
 | 
|---|
| [ba3706f] | 628 |                                 stmtsToAddBefore.push_back( new DeclStmt( obj ) );
 | 
|---|
| [adcc065] | 629 |                         } // for
 | 
|---|
| [c2931ea] | 630 |                         for ( ObjectDecl * obj : returnDecls ) {
 | 
|---|
| [ba3706f] | 631 |                                 stmtsToAddBefore.push_back( new DeclStmt( obj ) );
 | 
|---|
| [adcc065] | 632 |                         } // for
 | 
|---|
| [db4ecc5] | 633 | 
 | 
|---|
| [c2931ea] | 634 |                         // add destructors after current statement
 | 
|---|
 | 635 |                         for ( Expression * dtor : dtors ) {
 | 
|---|
| [ee61248] | 636 |                                 // take relevant bindings from environment
 | 
|---|
 | 637 |                                 assert( ! dtor->env );
 | 
|---|
| [b8baa37] | 638 |                                 dtor->env =  maybeClone( env );
 | 
|---|
| [ba3706f] | 639 |                                 stmtsToAddAfter.push_back( new ExprStmt( dtor ) );
 | 
|---|
| [adcc065] | 640 |                         } // for
 | 
|---|
| [db4ecc5] | 641 | 
 | 
|---|
| [c0714bf] | 642 |                         ObjectDecl * returnDecl = returnDecls.empty() ? nullptr : returnDecls.front();
 | 
|---|
| [c2931ea] | 643 |                         Expression * callExpr = impCpCtorExpr->get_callExpr();
 | 
|---|
 | 644 | 
 | 
|---|
 | 645 |                         CP_CTOR_PRINT( std::cerr << "Coming out the back..." << impCpCtorExpr << std::endl; )
 | 
|---|
 | 646 | 
 | 
|---|
 | 647 |                         // detach fields from wrapper node so that it can be deleted without deleting too much
 | 
|---|
 | 648 |                         dtors.clear();
 | 
|---|
 | 649 |                         tempDecls.clear();
 | 
|---|
 | 650 |                         returnDecls.clear();
 | 
|---|
| [c0714bf] | 651 |                         impCpCtorExpr->set_callExpr( nullptr );
 | 
|---|
 | 652 |                         std::swap( impCpCtorExpr->env, callExpr->env );
 | 
|---|
 | 653 |                         assert( impCpCtorExpr->env == nullptr );
 | 
|---|
| [c2931ea] | 654 |                         delete impCpCtorExpr;
 | 
|---|
 | 655 | 
 | 
|---|
 | 656 |                         if ( returnDecl ) {
 | 
|---|
| [f5c3b6c] | 657 |                                 ApplicationExpr * assign = createBitwiseAssignment( new VariableExpr( returnDecl ), callExpr );
 | 
|---|
| [c2931ea] | 658 |                                 Expression * retExpr = new CommaExpr( assign, new VariableExpr( returnDecl ) );
 | 
|---|
| [31f379c] | 659 |                                 // move env from callExpr to retExpr
 | 
|---|
| [50377a4] | 660 |                                 std::swap( retExpr->env, callExpr->env );
 | 
|---|
| [c2931ea] | 661 |                                 return retExpr;
 | 
|---|
 | 662 |                         } else {
 | 
|---|
 | 663 |                                 return callExpr;
 | 
|---|
| [adcc065] | 664 |                         } // if
 | 
|---|
| [4ffdd63] | 665 |                 }
 | 
|---|
| [c2931ea] | 666 | 
 | 
|---|
| [dc2334c] | 667 |                 void FixCopyCtors::premutate( StmtExpr * stmtExpr ) {
 | 
|---|
| [65aca88] | 668 |                         // function call temporaries should be placed at statement-level, rather than nested inside of a new statement expression,
 | 
|---|
 | 669 |                         // since temporaries can be shared across sub-expressions, e.g.
 | 
|---|
 | 670 |                         //   [A, A] f();
 | 
|---|
 | 671 |                         //   g([A] x, [A] y);
 | 
|---|
| [dc2334c] | 672 |                         //   g(f());
 | 
|---|
| [65aca88] | 673 |                         // f is executed once, so the return temporary is shared across the tuple constructors for x and y.
 | 
|---|
| [dc2334c] | 674 |                         // Explicitly mutating children instead of mutating the inner compound statment forces the temporaries to be added
 | 
|---|
 | 675 |                         // to the outer context, rather than inside of the statement expression.
 | 
|---|
 | 676 |                         visit_children = false;
 | 
|---|
| [9fe33947] | 677 |                         std::list< Statement * > & stmts = stmtExpr->statements->get_kids();
 | 
|---|
| [65aca88] | 678 |                         for ( Statement *& stmt : stmts ) {
 | 
|---|
| [dc2334c] | 679 |                                 stmt = stmt->acceptMutator( *visitor );
 | 
|---|
| [65aca88] | 680 |                         } // for
 | 
|---|
| [9fe33947] | 681 |                         assert( stmtExpr->result );
 | 
|---|
 | 682 |                         Type * result = stmtExpr->result;
 | 
|---|
| [31f379c] | 683 |                         if ( ! result->isVoid() ) {
 | 
|---|
| [9fe33947] | 684 |                                 for ( ObjectDecl * obj : stmtExpr->returnDecls ) {
 | 
|---|
| [ba3706f] | 685 |                                         stmtsToAddBefore.push_back( new DeclStmt( obj ) );
 | 
|---|
| [31f379c] | 686 |                                 } // for
 | 
|---|
 | 687 |                                 // add destructors after current statement
 | 
|---|
| [9fe33947] | 688 |                                 for ( Expression * dtor : stmtExpr->dtors ) {
 | 
|---|
| [ba3706f] | 689 |                                         stmtsToAddAfter.push_back( new ExprStmt( dtor ) );
 | 
|---|
| [31f379c] | 690 |                                 } // for
 | 
|---|
 | 691 |                                 // must have a non-empty body, otherwise it wouldn't have a result
 | 
|---|
| [dc2334c] | 692 |                                 assert( ! stmts.empty() );
 | 
|---|
| [6dfa2e1] | 693 |                                 assertf( ! stmtExpr->returnDecls.empty() || stmtExpr->dtors.empty(), "StmtExpr returns non-void, but no return decls: %s", toString( stmtExpr ).c_str() );
 | 
|---|
 | 694 |                                 // if there is a return decl, add a use as the last statement; will not have return decl on non-constructable returns
 | 
|---|
 | 695 |                                 if ( ! stmtExpr->returnDecls.empty() ) {
 | 
|---|
 | 696 |                                         stmts.push_back( new ExprStmt( new VariableExpr( stmtExpr->returnDecls.front() ) ) );
 | 
|---|
 | 697 |                                 }
 | 
|---|
| [9fe33947] | 698 |                                 stmtExpr->returnDecls.clear();
 | 
|---|
 | 699 |                                 stmtExpr->dtors.clear();
 | 
|---|
| [31f379c] | 700 |                         }
 | 
|---|
| [9fe33947] | 701 |                         assert( stmtExpr->returnDecls.empty() );
 | 
|---|
 | 702 |                         assert( stmtExpr->dtors.empty() );
 | 
|---|
| [31f379c] | 703 |                 }
 | 
|---|
 | 704 | 
 | 
|---|
| [dc2334c] | 705 |                 void FixCopyCtors::premutate( UniqueExpr * unqExpr ) {
 | 
|---|
 | 706 |                         visit_children = false;
 | 
|---|
| [597db97f] | 707 |                         unqCount[ unqExpr->get_id() ]--;
 | 
|---|
 | 708 |                         static std::unordered_map< int, std::list< Statement * > > dtors;
 | 
|---|
| [141b786] | 709 |                         static std::unordered_map< int, UniqueExpr * > unqMap;
 | 
|---|
 | 710 |                         // has to be done to clean up ImplicitCopyCtorExpr nodes, even when this node was skipped in previous passes
 | 
|---|
 | 711 |                         if ( unqMap.count( unqExpr->get_id() ) ) {
 | 
|---|
 | 712 |                                 // take data from other UniqueExpr to ensure consistency
 | 
|---|
 | 713 |                                 delete unqExpr->get_expr();
 | 
|---|
 | 714 |                                 unqExpr->set_expr( unqMap[unqExpr->get_id()]->get_expr()->clone() );
 | 
|---|
 | 715 |                                 delete unqExpr->get_result();
 | 
|---|
 | 716 |                                 unqExpr->set_result( maybeClone( unqExpr->get_expr()->get_result() ) );
 | 
|---|
| [597db97f] | 717 |                                 if ( unqCount[ unqExpr->get_id() ] == 0 ) {  // insert destructor after the last use of the unique expression
 | 
|---|
| [edbdbe6] | 718 |                                         stmtsToAddAfter.splice( stmtsToAddAfter.end(), dtors[ unqExpr->get_id() ] );
 | 
|---|
| [597db97f] | 719 |                                 }
 | 
|---|
| [dc2334c] | 720 |                                 return;
 | 
|---|
| [141b786] | 721 |                         }
 | 
|---|
| [dc2334c] | 722 |                         PassVisitor<FixCopyCtors> fixer( unqCount );
 | 
|---|
| [597db97f] | 723 |                         unqExpr->set_expr( unqExpr->get_expr()->acceptMutator( fixer ) ); // stmtexprs contained should not be separately fixed, so this must occur after the lookup
 | 
|---|
| [dc2334c] | 724 |                         stmtsToAddBefore.splice( stmtsToAddBefore.end(), fixer.pass.stmtsToAddBefore );
 | 
|---|
| [141b786] | 725 |                         unqMap[unqExpr->get_id()] = unqExpr;
 | 
|---|
| [edbdbe6] | 726 |                         if ( unqCount[ unqExpr->get_id() ] == 0 ) {  // insert destructor after the last use of the unique expression
 | 
|---|
 | 727 |                                 stmtsToAddAfter.splice( stmtsToAddAfter.end(), dtors[ unqExpr->get_id() ] );
 | 
|---|
 | 728 |                         } else { // remember dtors for last instance of unique expr
 | 
|---|
| [dc2334c] | 729 |                                 dtors[ unqExpr->get_id() ] = fixer.pass.stmtsToAddAfter;
 | 
|---|
| [141b786] | 730 |                         }
 | 
|---|
| [dc2334c] | 731 |                         return;
 | 
|---|
| [141b786] | 732 |                 }
 | 
|---|
 | 733 | 
 | 
|---|
| [5363fdf] | 734 |                 DeclarationWithType * FixInit::postmutate( ObjectDecl *objDecl ) {
 | 
|---|
| [aff3af4] | 735 |                         // since this removes the init field from objDecl, it must occur after children are mutated (i.e. postmutate)
 | 
|---|
| [c2931ea] | 736 |                         if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) {
 | 
|---|
 | 737 |                                 // a decision should have been made by the resolver, so ctor and init are not both non-NULL
 | 
|---|
 | 738 |                                 assert( ! ctorInit->get_ctor() || ! ctorInit->get_init() );
 | 
|---|
 | 739 |                                 if ( Statement * ctor = ctorInit->get_ctor() ) {
 | 
|---|
| [08d5507b] | 740 |                                         if ( objDecl->get_storageClasses().is_static ) {
 | 
|---|
| [72e9222] | 741 |                                                 // originally wanted to take advantage of gcc nested functions, but
 | 
|---|
| [f9cebb5] | 742 |                                                 // we get memory errors with this approach. To remedy this, the static
 | 
|---|
 | 743 |                                                 // variable is hoisted when the destructor needs to be called.
 | 
|---|
| [72e9222] | 744 |                                                 //
 | 
|---|
| [c2931ea] | 745 |                                                 // generate:
 | 
|---|
| [f9cebb5] | 746 |                                                 // static T __objName_static_varN;
 | 
|---|
| [72e9222] | 747 |                                                 // void __objName_dtor_atexitN() {
 | 
|---|
| [f9cebb5] | 748 |                                                 //   __dtor__...;
 | 
|---|
| [72e9222] | 749 |                                                 // }
 | 
|---|
 | 750 |                                                 // int f(...) {
 | 
|---|
 | 751 |                                                 //   ...
 | 
|---|
 | 752 |                                                 //   static bool __objName_uninitialized = true;
 | 
|---|
 | 753 |                                                 //   if (__objName_uninitialized) {
 | 
|---|
 | 754 |                                                 //     __ctor(__objName);
 | 
|---|
 | 755 |                                                 //     __objName_uninitialized = false;
 | 
|---|
| [f9cebb5] | 756 |                                                 //     atexit(__objName_dtor_atexitN);
 | 
|---|
| [c2931ea] | 757 |                                                 //   }
 | 
|---|
| [72e9222] | 758 |                                                 //   ...
 | 
|---|
| [c2931ea] | 759 |                                                 // }
 | 
|---|
 | 760 | 
 | 
|---|
| [72e9222] | 761 |                                                 static UniqueName dtorCallerNamer( "_dtor_atexit" );
 | 
|---|
 | 762 | 
 | 
|---|
 | 763 |                                                 // static bool __objName_uninitialized = true
 | 
|---|
| [c2931ea] | 764 |                                                 BasicType * boolType = new BasicType( Type::Qualifiers(), BasicType::Bool );
 | 
|---|
| [579263a] | 765 |                                                 SingleInit * boolInitExpr = new SingleInit( new ConstantExpr( Constant::from_int( 1 ) ) );
 | 
|---|
| [68fe077a] | 766 |                                                 ObjectDecl * isUninitializedVar = new ObjectDecl( objDecl->get_mangleName() + "_uninitialized", Type::StorageClasses( Type::Static ), LinkageSpec::Cforall, 0, boolType, boolInitExpr );
 | 
|---|
| [c2931ea] | 767 |                                                 isUninitializedVar->fixUniqueId();
 | 
|---|
 | 768 | 
 | 
|---|
 | 769 |                                                 // __objName_uninitialized = false;
 | 
|---|
 | 770 |                                                 UntypedExpr * setTrue = new UntypedExpr( new NameExpr( "?=?" ) );
 | 
|---|
 | 771 |                                                 setTrue->get_args().push_back( new VariableExpr( isUninitializedVar ) );
 | 
|---|
| [d56e5bc] | 772 |                                                 setTrue->get_args().push_back( new ConstantExpr( Constant::from_int( 0 ) ) );
 | 
|---|
| [c2931ea] | 773 | 
 | 
|---|
 | 774 |                                                 // generate body of if
 | 
|---|
| [ba3706f] | 775 |                                                 CompoundStmt * initStmts = new CompoundStmt();
 | 
|---|
| [c2931ea] | 776 |                                                 std::list< Statement * > & body = initStmts->get_kids();
 | 
|---|
 | 777 |                                                 body.push_back( ctor );
 | 
|---|
| [ba3706f] | 778 |                                                 body.push_back( new ExprStmt( setTrue ) );
 | 
|---|
| [c2931ea] | 779 | 
 | 
|---|
 | 780 |                                                 // put it all together
 | 
|---|
| [ba3706f] | 781 |                                                 IfStmt * ifStmt = new IfStmt( new VariableExpr( isUninitializedVar ), initStmts, 0 );
 | 
|---|
 | 782 |                                                 stmtsToAddAfter.push_back( new DeclStmt( isUninitializedVar ) );
 | 
|---|
| [c2931ea] | 783 |                                                 stmtsToAddAfter.push_back( ifStmt );
 | 
|---|
| [72e9222] | 784 | 
 | 
|---|
| [a4dd728] | 785 |                                                 Statement * dtor = ctorInit->get_dtor();
 | 
|---|
| [62423350] | 786 |                                                 objDecl->set_init( nullptr );
 | 
|---|
 | 787 |                                                 ctorInit->set_ctor( nullptr );
 | 
|---|
| [a4dd728] | 788 |                                                 ctorInit->set_dtor( nullptr );
 | 
|---|
 | 789 |                                                 if ( dtor ) {
 | 
|---|
| [f9cebb5] | 790 |                                                         // if the object has a non-trivial destructor, have to
 | 
|---|
 | 791 |                                                         // hoist it and the object into the global space and
 | 
|---|
 | 792 |                                                         // call the destructor function with atexit.
 | 
|---|
 | 793 | 
 | 
|---|
| [a4dd728] | 794 |                                                         Statement * dtorStmt = dtor->clone();
 | 
|---|
| [f9cebb5] | 795 | 
 | 
|---|
 | 796 |                                                         // void __objName_dtor_atexitN(...) {...}
 | 
|---|
| [ba3706f] | 797 |                                                         FunctionDecl * dtorCaller = new FunctionDecl( objDecl->get_mangleName() + dtorCallerNamer.newName(), Type::StorageClasses( Type::Static ), LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt() );
 | 
|---|
| [f9cebb5] | 798 |                                                         dtorCaller->fixUniqueId();
 | 
|---|
| [c8dfcd3] | 799 |                                                         dtorCaller->get_statements()->push_back( dtorStmt );
 | 
|---|
| [f9cebb5] | 800 | 
 | 
|---|
 | 801 |                                                         // atexit(dtor_atexit);
 | 
|---|
 | 802 |                                                         UntypedExpr * callAtexit = new UntypedExpr( new NameExpr( "atexit" ) );
 | 
|---|
 | 803 |                                                         callAtexit->get_args().push_back( new VariableExpr( dtorCaller ) );
 | 
|---|
 | 804 | 
 | 
|---|
| [ba3706f] | 805 |                                                         body.push_back( new ExprStmt( callAtexit ) );
 | 
|---|
| [f9cebb5] | 806 | 
 | 
|---|
 | 807 |                                                         // hoist variable and dtor caller decls to list of decls that will be added into global scope
 | 
|---|
 | 808 |                                                         staticDtorDecls.push_back( objDecl );
 | 
|---|
 | 809 |                                                         staticDtorDecls.push_back( dtorCaller );
 | 
|---|
 | 810 | 
 | 
|---|
 | 811 |                                                         // need to rename object uniquely since it now appears
 | 
|---|
 | 812 |                                                         // at global scope and there could be multiple function-scoped
 | 
|---|
 | 813 |                                                         // static variables with the same name in different functions.
 | 
|---|
| [c8dfcd3] | 814 |                                                         // Note: it isn't sufficient to modify only the mangleName, because
 | 
|---|
 | 815 |                                                         // then subsequent Indexer passes can choke on seeing the object's name
 | 
|---|
 | 816 |                                                         // if another object has the same name and type. An unfortunate side-effect
 | 
|---|
 | 817 |                                                         // of renaming the object is that subsequent NameExprs may fail to resolve,
 | 
|---|
 | 818 |                                                         // but there shouldn't be any remaining past this point.
 | 
|---|
| [f9cebb5] | 819 |                                                         static UniqueName staticNamer( "_static_var" );
 | 
|---|
| [c8dfcd3] | 820 |                                                         objDecl->set_name( objDecl->get_name() + staticNamer.newName() );
 | 
|---|
 | 821 |                                                         objDecl->set_mangleName( SymTab::Mangler::mangle( objDecl ) );
 | 
|---|
| [f9cebb5] | 822 | 
 | 
|---|
 | 823 |                                                         // xxx - temporary hack: need to return a declaration, but want to hoist the current object out of this scope
 | 
|---|
 | 824 |                                                         // create a new object which is never used
 | 
|---|
 | 825 |                                                         static UniqueName dummyNamer( "_dummy" );
 | 
|---|
| [68fe077a] | 826 |                                                         ObjectDecl * dummy = new ObjectDecl( dummyNamer.newName(), Type::StorageClasses( Type::Static ), LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), 0, std::list< Attribute * >{ new Attribute("unused") } );
 | 
|---|
| [a4dd728] | 827 |                                                         delete ctorInit;
 | 
|---|
| [f9cebb5] | 828 |                                                         return dummy;
 | 
|---|
 | 829 |                                                 }
 | 
|---|
| [c2931ea] | 830 |                                         } else {
 | 
|---|
| [e3e16bc] | 831 |                                                 ImplicitCtorDtorStmt * implicit = strict_dynamic_cast< ImplicitCtorDtorStmt * > ( ctor );
 | 
|---|
| [5363fdf] | 832 |                                                 ExprStmt * ctorStmt = dynamic_cast< ExprStmt * >( implicit->callStmt );
 | 
|---|
| [233e4d9] | 833 |                                                 ApplicationExpr * ctorCall = nullptr;
 | 
|---|
| [5363fdf] | 834 |                                                 if ( ctorStmt && (ctorCall = isIntrinsicCallExpr( ctorStmt->expr )) && ctorCall->get_args().size() == 2 ) {
 | 
|---|
| [233e4d9] | 835 |                                                         // clean up intrinsic copy constructor calls by making them into SingleInits
 | 
|---|
| [e41306d] | 836 |                                                         Expression * ctorArg = ctorCall->args.back();
 | 
|---|
 | 837 |                                                         std::swap( ctorArg->env, ctorCall->env );
 | 
|---|
 | 838 |                                                         objDecl->init = new SingleInit( ctorArg );
 | 
|---|
 | 839 | 
 | 
|---|
| [5363fdf] | 840 |                                                         ctorCall->args.pop_back();
 | 
|---|
| [233e4d9] | 841 |                                                 } else {
 | 
|---|
 | 842 |                                                         stmtsToAddAfter.push_back( ctor );
 | 
|---|
| [5363fdf] | 843 |                                                         objDecl->init = nullptr;
 | 
|---|
 | 844 |                                                         ctorInit->ctor = nullptr;
 | 
|---|
| [233e4d9] | 845 |                                                 }
 | 
|---|
| [adcc065] | 846 |                                         } // if
 | 
|---|
| [5363fdf] | 847 |                                 } else if ( Initializer * init = ctorInit->init ) {
 | 
|---|
 | 848 |                                         objDecl->init = init;
 | 
|---|
 | 849 |                                         ctorInit->init = nullptr;
 | 
|---|
| [c2931ea] | 850 |                                 } else {
 | 
|---|
 | 851 |                                         // no constructor and no initializer, which is okay
 | 
|---|
| [5363fdf] | 852 |                                         objDecl->init = nullptr;
 | 
|---|
| [adcc065] | 853 |                                 } // if
 | 
|---|
| [c2931ea] | 854 |                                 delete ctorInit;
 | 
|---|
| [adcc065] | 855 |                         } // if
 | 
|---|
| [c2931ea] | 856 |                         return objDecl;
 | 
|---|
| [db4ecc5] | 857 |                 }
 | 
|---|
 | 858 | 
 | 
|---|
| [698ec72] | 859 |                 void ObjDeclCollector::previsit( CompoundStmt * ) {
 | 
|---|
 | 860 |                         GuardValue( curVars );
 | 
|---|
| [db4ecc5] | 861 |                 }
 | 
|---|
 | 862 | 
 | 
|---|
| [698ec72] | 863 |                 void ObjDeclCollector::previsit( DeclStmt * stmt ) {
 | 
|---|
| [4b2589a] | 864 |                         // keep track of all variables currently in scope
 | 
|---|
| [c2931ea] | 865 |                         if ( ObjectDecl * objDecl = dynamic_cast< ObjectDecl * > ( stmt->get_decl() ) ) {
 | 
|---|
| [62423350] | 866 |                                 curVars.push_back( objDecl );
 | 
|---|
| [adcc065] | 867 |                         } // if
 | 
|---|
| [db4ecc5] | 868 |                 }
 | 
|---|
 | 869 | 
 | 
|---|
| [698ec72] | 870 |                 void LabelFinder::previsit( Statement * stmt ) {
 | 
|---|
| [4b2589a] | 871 |                         // for each label, remember the variables in scope at that label.
 | 
|---|
| [c2931ea] | 872 |                         for ( Label l : stmt->get_labels() ) {
 | 
|---|
 | 873 |                                 vars[l] = curVars;
 | 
|---|
| [adcc065] | 874 |                         } // for
 | 
|---|
| [71f4e4f] | 875 |                 }
 | 
|---|
| [f1e012b] | 876 | 
 | 
|---|
| [698ec72] | 877 |                 void LabelFinder::previsit( CompoundStmt * stmt ) {
 | 
|---|
 | 878 |                         previsit( (Statement *)stmt );
 | 
|---|
 | 879 |                         Parent::previsit( stmt );
 | 
|---|
 | 880 |                 }
 | 
|---|
 | 881 | 
 | 
|---|
 | 882 |                 void LabelFinder::previsit( DeclStmt * stmt ) {
 | 
|---|
 | 883 |                         previsit( (Statement *)stmt );
 | 
|---|
 | 884 |                         Parent::previsit( stmt );
 | 
|---|
 | 885 |                 }
 | 
|---|
 | 886 | 
 | 
|---|
 | 887 | 
 | 
|---|
| [ec79847] | 888 |                 template<typename Iterator, typename OutputIterator>
 | 
|---|
 | 889 |                 void insertDtors( Iterator begin, Iterator end, OutputIterator out ) {
 | 
|---|
 | 890 |                         for ( Iterator it = begin ; it != end ; ++it ) {
 | 
|---|
| [adcc065] | 891 |                                 // extract destructor statement from the object decl and insert it into the output. Note that this is
 | 
|---|
 | 892 |                                 // only called on lists of non-static objects with implicit non-intrinsic dtors, so if the user manually
 | 
|---|
 | 893 |                                 // calls an intrinsic dtor then the call must (and will) still be generated since the argument may
 | 
|---|
 | 894 |                                 // contain side effects.
 | 
|---|
| [c2931ea] | 895 |                                 ObjectDecl * objDecl = *it;
 | 
|---|
 | 896 |                                 ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() );
 | 
|---|
 | 897 |                                 assert( ctorInit && ctorInit->get_dtor() );
 | 
|---|
 | 898 |                                 *out++ = ctorInit->get_dtor()->clone();
 | 
|---|
| [adcc065] | 899 |                         } // for
 | 
|---|
| [f1e012b] | 900 |                 }
 | 
|---|
| [39786813] | 901 | 
 | 
|---|
| [698ec72] | 902 |                 void InsertDtors::previsit( ObjectDecl * objDecl ) {
 | 
|---|
| [c2931ea] | 903 |                         // remember non-static destructed objects so that their destructors can be inserted later
 | 
|---|
| [08d5507b] | 904 |                         if ( ! objDecl->get_storageClasses().is_static ) {
 | 
|---|
| [c2931ea] | 905 |                                 if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) {
 | 
|---|
 | 906 |                                         // a decision should have been made by the resolver, so ctor and init are not both non-NULL
 | 
|---|
 | 907 |                                         assert( ! ctorInit->get_ctor() || ! ctorInit->get_init() );
 | 
|---|
 | 908 |                                         Statement * dtor = ctorInit->get_dtor();
 | 
|---|
| [e4d6335] | 909 |                                         // don't need to call intrinsic dtor, because it does nothing, but
 | 
|---|
 | 910 |                                         // non-intrinsic dtors must be called
 | 
|---|
| [f9cebb5] | 911 |                                         if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) {
 | 
|---|
| [e4d6335] | 912 |                                                 // set dtor location to the object's location for error messages
 | 
|---|
 | 913 |                                                 ctorInit->dtor->location = objDecl->location;
 | 
|---|
| [c2931ea] | 914 |                                                 reverseDeclOrder.front().push_front( objDecl );
 | 
|---|
| [adcc065] | 915 |                                         } // if
 | 
|---|
 | 916 |                                 } // if
 | 
|---|
 | 917 |                         } // if
 | 
|---|
| [52c14b3] | 918 |                 }
 | 
|---|
 | 919 | 
 | 
|---|
| [698ec72] | 920 |                 void InsertDtors::previsit( FunctionDecl * funcDecl ) {
 | 
|---|
| [52c14b3] | 921 |                         // each function needs to have its own set of labels
 | 
|---|
| [698ec72] | 922 |                         GuardValue( labelVars );
 | 
|---|
| [52c14b3] | 923 |                         labelVars.clear();
 | 
|---|
| [680620d] | 924 |                         // LabelFinder does not recurse into FunctionDecl, so need to visit
 | 
|---|
 | 925 |                         // its children manually.
 | 
|---|
| [698ec72] | 926 |                         maybeAccept( funcDecl->type, finder );
 | 
|---|
 | 927 |                         maybeAccept( funcDecl->statements, finder );
 | 
|---|
| [52c14b3] | 928 | 
 | 
|---|
| [698ec72] | 929 |                         // all labels for this function have been collected, insert destructors as appropriate via implicit recursion.
 | 
|---|
| [52c14b3] | 930 |                 }
 | 
|---|
 | 931 | 
 | 
|---|
| [698ec72] | 932 |                 void InsertDtors::previsit( CompoundStmt * compoundStmt ) {
 | 
|---|
| [adcc065] | 933 |                         // visit statements - this will also populate reverseDeclOrder list.  don't want to dump all destructors
 | 
|---|
 | 934 |                         // when block is left, just the destructors associated with variables defined in this block, so push a new
 | 
|---|
 | 935 |                         // list to the top of the stack so that we can differentiate scopes
 | 
|---|
| [c2931ea] | 936 |                         reverseDeclOrder.push_front( OrderedDecls() );
 | 
|---|
| [698ec72] | 937 |                         Parent::previsit( compoundStmt );
 | 
|---|
 | 938 |                 }
 | 
|---|
| [39786813] | 939 | 
 | 
|---|
| [698ec72] | 940 |                 void InsertDtors::postvisit( CompoundStmt * compoundStmt ) {
 | 
|---|
| [0661678] | 941 |                         // add destructors for the current scope that we're exiting, unless the last statement is a return, which
 | 
|---|
 | 942 |                         // causes unreachable code warnings
 | 
|---|
| [c2931ea] | 943 |                         std::list< Statement * > & statements = compoundStmt->get_kids();
 | 
|---|
| [0661678] | 944 |                         if ( ! statements.empty() && ! dynamic_cast< ReturnStmt * >( statements.back() ) ) {
 | 
|---|
 | 945 |                                 insertDtors( reverseDeclOrder.front().begin(), reverseDeclOrder.front().end(), back_inserter( statements ) );
 | 
|---|
 | 946 |                         }
 | 
|---|
| [c2931ea] | 947 |                         reverseDeclOrder.pop_front();
 | 
|---|
| [39786813] | 948 |                 }
 | 
|---|
 | 949 | 
 | 
|---|
| [698ec72] | 950 |                 void InsertDtors::previsit( ReturnStmt * ) {
 | 
|---|
| [4b2589a] | 951 |                         // return exits all scopes, so dump destructors for all scopes
 | 
|---|
| [c2931ea] | 952 |                         for ( OrderedDecls & od : reverseDeclOrder ) {
 | 
|---|
| [698ec72] | 953 |                                 insertDtors( od.begin(), od.end(), back_inserter( stmtsToAddBefore ) );
 | 
|---|
| [adcc065] | 954 |                         } // for
 | 
|---|
| [39786813] | 955 |                 }
 | 
|---|
| [f1e012b] | 956 | 
 | 
|---|
| [adcc065] | 957 |                 // Handle break/continue/goto in the same manner as C++.  Basic idea: any objects that are in scope at the
 | 
|---|
 | 958 |                 // BranchStmt but not at the labelled (target) statement must be destructed.  If there are any objects in scope
 | 
|---|
 | 959 |                 // at the target location but not at the BranchStmt then those objects would be uninitialized so notify the user
 | 
|---|
 | 960 |                 // of the error.  See C++ Reference 6.6 Jump Statements for details.
 | 
|---|
| [c2931ea] | 961 |                 void InsertDtors::handleGoto( BranchStmt * stmt ) {
 | 
|---|
| [5809461] | 962 |                         // can't do anything for computed goto
 | 
|---|
 | 963 |                         if ( stmt->computedTarget ) return;
 | 
|---|
 | 964 | 
 | 
|---|
 | 965 |                         assertf( stmt->get_target() != "", "BranchStmt missing a label: %s", toString( stmt ).c_str() );
 | 
|---|
| [c2931ea] | 966 |                         // S_L = lvars = set of objects in scope at label definition
 | 
|---|
 | 967 |                         // S_G = curVars = set of objects in scope at goto statement
 | 
|---|
 | 968 |                         ObjectSet & lvars = labelVars[ stmt->get_target() ];
 | 
|---|
 | 969 | 
 | 
|---|
 | 970 |                         DTOR_PRINT(
 | 
|---|
 | 971 |                                 std::cerr << "at goto label: " << stmt->get_target().get_name() << std::endl;
 | 
|---|
 | 972 |                                 std::cerr << "S_G = " << printSet( curVars ) << std::endl;
 | 
|---|
 | 973 |                                 std::cerr << "S_L = " << printSet( lvars ) << std::endl;
 | 
|---|
 | 974 |                         )
 | 
|---|
 | 975 | 
 | 
|---|
 | 976 |                         ObjectSet diff;
 | 
|---|
 | 977 |                         // S_L-S_G results in set of objects whose construction is skipped - it's an error if this set is non-empty
 | 
|---|
 | 978 |                         std::set_difference( lvars.begin(), lvars.end(), curVars.begin(), curVars.end(), std::inserter( diff, diff.begin() ) );
 | 
|---|
 | 979 |                         DTOR_PRINT(
 | 
|---|
 | 980 |                                 std::cerr << "S_L-S_G = " << printSet( diff ) << std::endl;
 | 
|---|
 | 981 |                         )
 | 
|---|
 | 982 |                         if ( ! diff.empty() ) {
 | 
|---|
| [a16764a6] | 983 |                                 SemanticError( stmt, std::string("jump to label '") + stmt->get_target().get_name() + "' crosses initialization of " + (*diff.begin())->get_name() + " " );
 | 
|---|
| [adcc065] | 984 |                         } // if
 | 
|---|
| [c2931ea] | 985 |                         // S_G-S_L results in set of objects that must be destructed
 | 
|---|
 | 986 |                         diff.clear();
 | 
|---|
 | 987 |                         std::set_difference( curVars.begin(), curVars.end(), lvars.begin(), lvars.end(), std::inserter( diff, diff.end() ) );
 | 
|---|
 | 988 |                         DTOR_PRINT(
 | 
|---|
 | 989 |                                 std::cerr << "S_G-S_L = " << printSet( diff ) << std::endl;
 | 
|---|
 | 990 |                         )
 | 
|---|
 | 991 |                         if ( ! diff.empty() ) {
 | 
|---|
| [62423350] | 992 |                                 // create an auxilliary set for fast lookup -- can't make diff a set, because diff ordering should be consistent for error messages.
 | 
|---|
 | 993 |                                 std::unordered_set<ObjectDecl *> needsDestructor( diff.begin(), diff.end() );
 | 
|---|
 | 994 | 
 | 
|---|
| [c2931ea] | 995 |                                 // go through decl ordered list of objectdecl. for each element that occurs in diff, output destructor
 | 
|---|
 | 996 |                                 OrderedDecls ordered;
 | 
|---|
 | 997 |                                 for ( OrderedDecls & rdo : reverseDeclOrder ) {
 | 
|---|
 | 998 |                                         // add elements from reverseDeclOrder into ordered if they occur in diff - it is key that this happens in reverse declaration order.
 | 
|---|
| [62423350] | 999 |                                         copy_if( rdo.begin(), rdo.end(), back_inserter( ordered ), [&]( ObjectDecl * objDecl ) { return needsDestructor.count( objDecl ); } );
 | 
|---|
| [adcc065] | 1000 |                                 } // for
 | 
|---|
| [698ec72] | 1001 |                                 insertDtors( ordered.begin(), ordered.end(), back_inserter( stmtsToAddBefore ) );
 | 
|---|
| [adcc065] | 1002 |                         } // if
 | 
|---|
| [c2931ea] | 1003 |                 }
 | 
|---|
| [39786813] | 1004 | 
 | 
|---|
| [698ec72] | 1005 |                 void InsertDtors::previsit( BranchStmt * stmt ) {
 | 
|---|
| [c2931ea] | 1006 |                         switch( stmt->get_type() ) {
 | 
|---|
| [adcc065] | 1007 |                           case BranchStmt::Continue:
 | 
|---|
 | 1008 |                           case BranchStmt::Break:
 | 
|---|
 | 1009 |                                 // could optimize the break/continue case, because the S_L-S_G check is unnecessary (this set should
 | 
|---|
 | 1010 |                                 // always be empty), but it serves as a small sanity check.
 | 
|---|
 | 1011 |                           case BranchStmt::Goto:
 | 
|---|
 | 1012 |                                 handleGoto( stmt );
 | 
|---|
 | 1013 |                                 break;
 | 
|---|
 | 1014 |                           default:
 | 
|---|
 | 1015 |                                 assert( false );
 | 
|---|
 | 1016 |                         } // switch
 | 
|---|
| [c2931ea] | 1017 |                 }
 | 
|---|
| [79970ed] | 1018 | 
 | 
|---|
 | 1019 |                 bool checkWarnings( FunctionDecl * funcDecl ) {
 | 
|---|
 | 1020 |                         // only check for warnings if the current function is a user-defined
 | 
|---|
 | 1021 |                         // constructor or destructor
 | 
|---|
 | 1022 |                         if ( ! funcDecl ) return false;
 | 
|---|
 | 1023 |                         if ( ! funcDecl->get_statements() ) return false;
 | 
|---|
| [bff227f] | 1024 |                         return CodeGen::isCtorDtor( funcDecl->get_name() ) && ! LinkageSpec::isOverridable( funcDecl->get_linkage() );
 | 
|---|
| [79970ed] | 1025 |                 }
 | 
|---|
 | 1026 | 
 | 
|---|
| [b3fc977] | 1027 |                 void GenStructMemberCalls::premutate( FunctionDecl * funcDecl ) {
 | 
|---|
| [5363fdf] | 1028 |                         GuardValue( function );
 | 
|---|
| [9a707e4e] | 1029 |                         GuardValue( unhandled );
 | 
|---|
 | 1030 |                         GuardValue( usedUninit );
 | 
|---|
 | 1031 |                         GuardValue( thisParam );
 | 
|---|
 | 1032 |                         GuardValue( isCtor );
 | 
|---|
 | 1033 |                         GuardValue( structDecl );
 | 
|---|
| [a16764a6] | 1034 |                         errors = SemanticErrorException();  // clear previous errors
 | 
|---|
| [c8dfcd3] | 1035 | 
 | 
|---|
 | 1036 |                         // need to start with fresh sets
 | 
|---|
 | 1037 |                         unhandled.clear();
 | 
|---|
 | 1038 |                         usedUninit.clear();
 | 
|---|
| [79970ed] | 1039 | 
 | 
|---|
 | 1040 |                         function = funcDecl;
 | 
|---|
| [bff227f] | 1041 |                         isCtor = CodeGen::isConstructor( function->get_name() );
 | 
|---|
| [c8dfcd3] | 1042 |                         if ( checkWarnings( function ) ) {
 | 
|---|
 | 1043 |                                 FunctionType * type = function->get_functionType();
 | 
|---|
| [79970ed] | 1044 |                                 assert( ! type->get_parameters().empty() );
 | 
|---|
| [e3e16bc] | 1045 |                                 thisParam = strict_dynamic_cast< ObjectDecl * >( type->get_parameters().front() );
 | 
|---|
| [0a81c3f] | 1046 |                                 Type * thisType = getPointerBase( thisParam->get_type() );
 | 
|---|
 | 1047 |                                 StructInstType * structType = dynamic_cast< StructInstType * >( thisType );
 | 
|---|
| [79970ed] | 1048 |                                 if ( structType ) {
 | 
|---|
| [44f6341] | 1049 |                                         structDecl = structType->get_baseStruct();
 | 
|---|
| [79970ed] | 1050 |                                         for ( Declaration * member : structDecl->get_members() ) {
 | 
|---|
 | 1051 |                                                 if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( member ) ) {
 | 
|---|
 | 1052 |                                                         // record all of the struct type's members that need to be constructed or
 | 
|---|
 | 1053 |                                                         // destructed by the end of the function
 | 
|---|
 | 1054 |                                                         unhandled.insert( field );
 | 
|---|
 | 1055 |                                                 }
 | 
|---|
 | 1056 |                                         }
 | 
|---|
 | 1057 |                                 }
 | 
|---|
 | 1058 |                         }
 | 
|---|
| [9a707e4e] | 1059 |                 }
 | 
|---|
 | 1060 | 
 | 
|---|
| [b3fc977] | 1061 |                 DeclarationWithType * GenStructMemberCalls::postmutate( FunctionDecl * funcDecl ) {
 | 
|---|
| [c8dfcd3] | 1062 |                         // remove the unhandled objects from usedUninit, because a call is inserted
 | 
|---|
 | 1063 |                         // to handle them - only objects that are later constructed are used uninitialized.
 | 
|---|
| [64ac636] | 1064 |                         std::map< DeclarationWithType *, CodeLocation > diff;
 | 
|---|
 | 1065 |                         // need the comparator since usedUninit and unhandled have different types
 | 
|---|
 | 1066 |                         struct comp_t {
 | 
|---|
 | 1067 |                                 typedef decltype(usedUninit)::value_type usedUninit_t;
 | 
|---|
 | 1068 |                                 typedef decltype(unhandled)::value_type unhandled_t;
 | 
|---|
 | 1069 |                                 bool operator()(usedUninit_t x, unhandled_t y) { return x.first < y; }
 | 
|---|
 | 1070 |                                 bool operator()(unhandled_t x, usedUninit_t y) { return x < y.first; }
 | 
|---|
 | 1071 |                         } comp;
 | 
|---|
 | 1072 |                         std::set_difference( usedUninit.begin(), usedUninit.end(), unhandled.begin(), unhandled.end(), std::inserter( diff, diff.begin() ), comp );
 | 
|---|
 | 1073 |                         for ( auto p : diff ) {
 | 
|---|
 | 1074 |                                 DeclarationWithType * member = p.first;
 | 
|---|
 | 1075 |                                 CodeLocation loc = p.second;
 | 
|---|
 | 1076 |                                 // xxx - make error message better by also tracking the location that the object is constructed at?
 | 
|---|
 | 1077 |                                 emit( loc, "in ", CodeGen::genPrettyType( function->get_functionType(), function->get_name() ), ", field ", member->get_name(), " used before being constructed" );
 | 
|---|
| [79970ed] | 1078 |                         }
 | 
|---|
 | 1079 | 
 | 
|---|
| [c8dfcd3] | 1080 |                         if ( ! unhandled.empty() ) {
 | 
|---|
| [4618319] | 1081 |                                 // need to explicitly re-add function parameters to the indexer in order to resolve copy constructors
 | 
|---|
| [9a707e4e] | 1082 |                                 auto guard = makeFuncGuard( [this]() { indexer.enterScope(); }, [this]() { indexer.leaveScope(); } );
 | 
|---|
| [5fe35d6] | 1083 |                                 indexer.addFunctionType( function->type );
 | 
|---|
| [44f6341] | 1084 | 
 | 
|---|
 | 1085 |                                 // need to iterate through members in reverse in order for
 | 
|---|
 | 1086 |                                 // ctor/dtor statements to come out in the right order
 | 
|---|
| [1ba88a0] | 1087 |                                 for ( Declaration * member : reverseIterate( structDecl->get_members() ) ) {
 | 
|---|
| [44f6341] | 1088 |                                         DeclarationWithType * field = dynamic_cast< DeclarationWithType * >( member );
 | 
|---|
 | 1089 |                                         // skip non-DWT members
 | 
|---|
 | 1090 |                                         if ( ! field ) continue;
 | 
|---|
| [05807e9] | 1091 |                                         // skip non-constructable members
 | 
|---|
 | 1092 |                                         if ( ! tryConstruct( field ) ) continue;
 | 
|---|
| [44f6341] | 1093 |                                         // skip handled members
 | 
|---|
 | 1094 |                                         if ( ! unhandled.count( field ) ) continue;
 | 
|---|
 | 1095 | 
 | 
|---|
 | 1096 |                                         // insert and resolve default/copy constructor call for each field that's unhandled
 | 
|---|
| [c8dfcd3] | 1097 |                                         std::list< Statement * > stmt;
 | 
|---|
| [5fe35d6] | 1098 |                                         Expression * arg2 = nullptr;
 | 
|---|
| [4d4882a] | 1099 |                                         if ( isCopyConstructor( function ) ) {
 | 
|---|
| [44f6341] | 1100 |                                                 // if copy ctor, need to pass second-param-of-this-function.field
 | 
|---|
| [4d4882a] | 1101 |                                                 std::list< DeclarationWithType * > & params = function->get_functionType()->get_parameters();
 | 
|---|
 | 1102 |                                                 assert( params.size() == 2 );
 | 
|---|
| [44f6341] | 1103 |                                                 arg2 = new MemberExpr( field, new VariableExpr( params.back() ) );
 | 
|---|
| [4d4882a] | 1104 |                                         }
 | 
|---|
 | 1105 |                                         InitExpander srcParam( arg2 );
 | 
|---|
| [4618319] | 1106 |                                         // cast away reference type and construct field.
 | 
|---|
 | 1107 |                                         Expression * thisExpr = new CastExpr( new VariableExpr( thisParam ), thisParam->get_type()->stripReferences()->clone() );
 | 
|---|
 | 1108 |                                         Expression * memberDest = new MemberExpr( field, thisExpr );
 | 
|---|
 | 1109 |                                         SymTab::genImplicitCall( srcParam, memberDest, function->get_name(), back_inserter( stmt ), field, isCtor );
 | 
|---|
| [c8dfcd3] | 1110 | 
 | 
|---|
 | 1111 |                                         assert( stmt.size() <= 1 );
 | 
|---|
 | 1112 |                                         if ( stmt.size() == 1 ) {
 | 
|---|
 | 1113 |                                                 Statement * callStmt = stmt.front();
 | 
|---|
 | 1114 | 
 | 
|---|
 | 1115 |                                                 try {
 | 
|---|
| [b3fc977] | 1116 |                                                         callStmt->acceptMutator( *visitor );
 | 
|---|
| [c8dfcd3] | 1117 |                                                         if ( isCtor ) {
 | 
|---|
 | 1118 |                                                                 function->get_statements()->push_front( callStmt );
 | 
|---|
 | 1119 |                                                         } else {
 | 
|---|
 | 1120 |                                                                 // destructor statements should be added at the end
 | 
|---|
 | 1121 |                                                                 function->get_statements()->push_back( callStmt );
 | 
|---|
 | 1122 |                                                         }
 | 
|---|
| [a16764a6] | 1123 |                                                 } catch ( SemanticErrorException & error ) {
 | 
|---|
| [64ac636] | 1124 |                                                         emit( funcDecl->location, "in ", CodeGen::genPrettyType( function->get_functionType(), function->get_name() ), ", field ", field->get_name(), " not explicitly ", isCtor ? "constructed" : "destructed",  " and no ", isCtor ? "default constructor" : "destructor", " found" );
 | 
|---|
| [c8dfcd3] | 1125 |                                                 }
 | 
|---|
 | 1126 |                                         }
 | 
|---|
 | 1127 |                                 }
 | 
|---|
 | 1128 |                         }
 | 
|---|
| [64ac636] | 1129 |                         if (! errors.isEmpty()) {
 | 
|---|
 | 1130 |                                 throw errors;
 | 
|---|
 | 1131 |                         }
 | 
|---|
| [b3fc977] | 1132 |                         return funcDecl;
 | 
|---|
| [79970ed] | 1133 |                 }
 | 
|---|
 | 1134 | 
 | 
|---|
| [4618319] | 1135 |                 /// true if expr is effectively just the 'this' parameter
 | 
|---|
 | 1136 |                 bool isThisExpression( Expression * expr, DeclarationWithType * thisParam ) {
 | 
|---|
 | 1137 |                         // TODO: there are more complicated ways to pass 'this' to a constructor, e.g. &*, *&, etc.
 | 
|---|
 | 1138 |                         if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( expr ) ) {
 | 
|---|
 | 1139 |                                 return varExpr->get_var() == thisParam;
 | 
|---|
 | 1140 |                         } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * > ( expr ) ) {
 | 
|---|
 | 1141 |                                 return isThisExpression( castExpr->get_arg(), thisParam );
 | 
|---|
 | 1142 |                         }
 | 
|---|
 | 1143 |                         return false;
 | 
|---|
 | 1144 |                 }
 | 
|---|
 | 1145 | 
 | 
|---|
 | 1146 |                 /// returns a MemberExpr if expr is effectively just member access on the 'this' parameter, else nullptr
 | 
|---|
 | 1147 |                 MemberExpr * isThisMemberExpr( Expression * expr, DeclarationWithType * thisParam ) {
 | 
|---|
 | 1148 |                         if ( MemberExpr * memberExpr = dynamic_cast< MemberExpr * >( expr ) ) {
 | 
|---|
 | 1149 |                                 if ( isThisExpression( memberExpr->get_aggregate(), thisParam ) ) {
 | 
|---|
 | 1150 |                                         return memberExpr;
 | 
|---|
 | 1151 |                                 }
 | 
|---|
 | 1152 |                         } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
 | 
|---|
 | 1153 |                                 return isThisMemberExpr( castExpr->get_arg(), thisParam );
 | 
|---|
 | 1154 |                         }
 | 
|---|
 | 1155 |                         return nullptr;
 | 
|---|
 | 1156 |                 }
 | 
|---|
 | 1157 | 
 | 
|---|
| [b3fc977] | 1158 |                 void GenStructMemberCalls::premutate( ApplicationExpr * appExpr ) {
 | 
|---|
| [9a707e4e] | 1159 |                         if ( ! checkWarnings( function ) ) {
 | 
|---|
 | 1160 |                                 visit_children = false;
 | 
|---|
 | 1161 |                                 return;
 | 
|---|
 | 1162 |                         }
 | 
|---|
| [79970ed] | 1163 | 
 | 
|---|
 | 1164 |                         std::string fname = getFunctionName( appExpr );
 | 
|---|
 | 1165 |                         if ( fname == function->get_name() ) {
 | 
|---|
 | 1166 |                                 // call to same kind of function
 | 
|---|
 | 1167 |                                 Expression * firstParam = appExpr->get_args().front();
 | 
|---|
 | 1168 | 
 | 
|---|
| [4618319] | 1169 |                                 if ( isThisExpression( firstParam, thisParam ) ) {
 | 
|---|
| [79970ed] | 1170 |                                         // if calling another constructor on thisParam, assume that function handles
 | 
|---|
 | 1171 |                                         // all members - if it doesn't a warning will appear in that function.
 | 
|---|
| [4618319] | 1172 |                                         unhandled.clear();
 | 
|---|
 | 1173 |                                 } else if ( MemberExpr * memberExpr = isThisMemberExpr( firstParam, thisParam ) ) {
 | 
|---|
 | 1174 |                                         // if first parameter is a member expression on the this parameter,
 | 
|---|
 | 1175 |                                         // then remove the member from unhandled set.
 | 
|---|
 | 1176 |                                         if ( isThisExpression( memberExpr->get_aggregate(), thisParam ) ) {
 | 
|---|
 | 1177 |                                                 unhandled.erase( memberExpr->get_member() );
 | 
|---|
| [79970ed] | 1178 |                                         }
 | 
|---|
 | 1179 |                                 }
 | 
|---|
 | 1180 |                         }
 | 
|---|
 | 1181 |                 }
 | 
|---|
 | 1182 | 
 | 
|---|
| [b3fc977] | 1183 |                 void GenStructMemberCalls::premutate( MemberExpr * memberExpr ) {
 | 
|---|
| [9a707e4e] | 1184 |                         if ( ! checkWarnings( function ) || ! isCtor ) {
 | 
|---|
 | 1185 |                                 visit_children = false;
 | 
|---|
 | 1186 |                                 return;
 | 
|---|
 | 1187 |                         }
 | 
|---|
| [79970ed] | 1188 | 
 | 
|---|
| [4618319] | 1189 |                         if ( isThisExpression( memberExpr->get_aggregate(), thisParam ) ) {
 | 
|---|
 | 1190 |                                 if ( unhandled.count( memberExpr->get_member() ) ) {
 | 
|---|
 | 1191 |                                         // emit a warning because a member was used before it was constructed
 | 
|---|
 | 1192 |                                         usedUninit.insert( { memberExpr->get_member(), memberExpr->location } );
 | 
|---|
| [79970ed] | 1193 |                                 }
 | 
|---|
 | 1194 |                         }
 | 
|---|
 | 1195 |                 }
 | 
|---|
| [3906301] | 1196 | 
 | 
|---|
 | 1197 |                 template< typename Visitor, typename... Params >
 | 
|---|
| [64ac636] | 1198 |                 void error( Visitor & v, CodeLocation loc, const Params &... params ) {
 | 
|---|
| [a16764a6] | 1199 |                         SemanticErrorException err( loc, toString( params... ) );
 | 
|---|
| [64ac636] | 1200 |                         v.errors.append( err );
 | 
|---|
| [3906301] | 1201 |                 }
 | 
|---|
 | 1202 | 
 | 
|---|
 | 1203 |                 template< typename... Params >
 | 
|---|
| [64ac636] | 1204 |                 void GenStructMemberCalls::emit( CodeLocation loc, const Params &... params ) {
 | 
|---|
| [3906301] | 1205 |                         // toggle warnings vs. errors here.
 | 
|---|
 | 1206 |                         // warn( params... );
 | 
|---|
| [64ac636] | 1207 |                         error( *this, loc, params... );
 | 
|---|
| [3906301] | 1208 |                 }
 | 
|---|
| [c8dfcd3] | 1209 | 
 | 
|---|
| [b3fc977] | 1210 |                 Expression * GenStructMemberCalls::postmutate( UntypedExpr * untypedExpr ) {
 | 
|---|
| [08da53d] | 1211 |                         Expression * newExpr = untypedExpr;
 | 
|---|
 | 1212 |                         ResolvExpr::findVoidExpression( newExpr, indexer );
 | 
|---|
 | 1213 |                         return newExpr;
 | 
|---|
| [c8dfcd3] | 1214 |                 }
 | 
|---|
| [b6fe7e6] | 1215 | 
 | 
|---|
| [696bf6e] | 1216 |                 Expression * FixCtorExprs::postmutate( ConstructorExpr * ctorExpr ) {
 | 
|---|
| [b6fe7e6] | 1217 |                         static UniqueName tempNamer( "_tmp_ctor_expr" );
 | 
|---|
| [f0121d7] | 1218 |                         // xxx - is the size check necessary?
 | 
|---|
| [d29fa5f] | 1219 |                         assert( ctorExpr->result && ctorExpr->get_result()->size() == 1 );
 | 
|---|
| [b7b8674] | 1220 | 
 | 
|---|
| [627f585] | 1221 |                         // xxx - this can be TupleAssignExpr now. Need to properly handle this case.
 | 
|---|
| [e3e16bc] | 1222 |                         ApplicationExpr * callExpr = strict_dynamic_cast< ApplicationExpr * > ( ctorExpr->get_callExpr() );
 | 
|---|
| [b6fe7e6] | 1223 |                         TypeSubstitution * env = ctorExpr->get_env();
 | 
|---|
 | 1224 |                         ctorExpr->set_callExpr( nullptr );
 | 
|---|
 | 1225 |                         ctorExpr->set_env( nullptr );
 | 
|---|
| [f5c3b6c] | 1226 | 
 | 
|---|
 | 1227 |                         // xxx - ideally we would reuse the temporary generated from the copy constructor passes from within firstArg if it exists and not generate a temporary if it's unnecessary.
 | 
|---|
 | 1228 |                         ObjectDecl * tmp = ObjectDecl::newObject( tempNamer.newName(), callExpr->args.front()->result->clone(), nullptr );
 | 
|---|
 | 1229 |                         declsToAddBefore.push_back( tmp );
 | 
|---|
| [8a6cf7e] | 1230 |                         delete ctorExpr;
 | 
|---|
| [b6fe7e6] | 1231 | 
 | 
|---|
| [696bf6e] | 1232 |                         // build assignment and replace constructor's first argument with new temporary
 | 
|---|
| [b6fe7e6] | 1233 |                         Expression *& firstArg = callExpr->get_args().front();
 | 
|---|
| [696bf6e] | 1234 |                         Expression * assign = new UntypedExpr( new NameExpr( "?=?" ), { new AddressExpr( new VariableExpr( tmp ) ), new AddressExpr( firstArg ) } );
 | 
|---|
| [8a6cf7e] | 1235 |                         firstArg = new VariableExpr( tmp );
 | 
|---|
 | 1236 | 
 | 
|---|
| [696bf6e] | 1237 |                         // resolve assignment and dispose of new env
 | 
|---|
| [08da53d] | 1238 |                         ResolvExpr::findVoidExpression( assign, indexer );
 | 
|---|
 | 1239 |                         delete assign->env;
 | 
|---|
 | 1240 |                         assign->env = nullptr;
 | 
|---|
| [696bf6e] | 1241 | 
 | 
|---|
| [8a6cf7e] | 1242 |                         // for constructor expr:
 | 
|---|
 | 1243 |                         //   T x;
 | 
|---|
 | 1244 |                         //   x{};
 | 
|---|
 | 1245 |                         // results in:
 | 
|---|
 | 1246 |                         //   T x;
 | 
|---|
 | 1247 |                         //   T & tmp;
 | 
|---|
 | 1248 |                         //   &tmp = &x, ?{}(tmp), tmp
 | 
|---|
| [08da53d] | 1249 |                         CommaExpr * commaExpr = new CommaExpr( assign, new CommaExpr( callExpr, new VariableExpr( tmp ) ) );
 | 
|---|
| [b6fe7e6] | 1250 |                         commaExpr->set_env( env );
 | 
|---|
 | 1251 |                         return commaExpr;
 | 
|---|
 | 1252 |                 }
 | 
|---|
| [c2931ea] | 1253 |         } // namespace
 | 
|---|
| [71f4e4f] | 1254 | } // namespace InitTweak
 | 
|---|
 | 1255 | 
 | 
|---|
 | 1256 | // Local Variables: //
 | 
|---|
 | 1257 | // tab-width: 4 //
 | 
|---|
 | 1258 | // mode: c++ //
 | 
|---|
 | 1259 | // compile-command: "make install" //
 | 
|---|
 | 1260 | // End: //
 | 
|---|