| [51587aa] | 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 | //
 | 
|---|
| [906e24d] | 7 | // Lvalue.cc --
 | 
|---|
| [51587aa] | 8 | //
 | 
|---|
 | 9 | // Author           : Richard C. Bilson
 | 
|---|
 | 10 | // Created On       : Mon May 18 07:44:20 2015
 | 
|---|
| [01aeade] | 11 | // Last Modified By : Peter A. Buhr
 | 
|---|
| [615a096] | 12 | // Last Modified On : Fri Mar 17 09:11:18 2017
 | 
|---|
 | 13 | // Update Count     : 5
 | 
|---|
| [51587aa] | 14 | //
 | 
|---|
| [51b73452] | 15 | 
 | 
|---|
| [e3e16bc] | 16 | #include <cassert>                       // for strict_dynamic_cast
 | 
|---|
| [08fc48f] | 17 | #include <string>                        // for string
 | 
|---|
| [51b73452] | 18 | 
 | 
|---|
| [8135d4c] | 19 | #include "Common/PassVisitor.h"
 | 
|---|
| [08fc48f] | 20 | #include "GenPoly.h"                     // for isPolyType
 | 
|---|
| [51b73452] | 21 | #include "Lvalue.h"
 | 
|---|
 | 22 | 
 | 
|---|
| [08fc48f] | 23 | #include "Parser/LinkageSpec.h"          // for Spec, isBuiltin, Intrinsic
 | 
|---|
 | 24 | #include "ResolvExpr/TypeEnvironment.h"  // for AssertionSet, OpenVarSet
 | 
|---|
 | 25 | #include "ResolvExpr/Unify.h"            // for unify
 | 
|---|
| [51b73452] | 26 | #include "ResolvExpr/typeops.h"
 | 
|---|
| [8135d4c] | 27 | #include "SymTab/Autogen.h"
 | 
|---|
| [08fc48f] | 28 | #include "SymTab/Indexer.h"              // for Indexer
 | 
|---|
 | 29 | #include "SynTree/Declaration.h"         // for Declaration, FunctionDecl
 | 
|---|
 | 30 | #include "SynTree/Expression.h"          // for Expression, ConditionalExpr
 | 
|---|
 | 31 | #include "SynTree/Mutator.h"             // for mutateAll, Mutator
 | 
|---|
 | 32 | #include "SynTree/Statement.h"           // for ReturnStmt, Statement (ptr o...
 | 
|---|
 | 33 | #include "SynTree/Type.h"                // for PointerType, Type, FunctionType
 | 
|---|
 | 34 | #include "SynTree/Visitor.h"             // for Visitor, acceptAll
 | 
|---|
| [1d776fd] | 35 | 
 | 
|---|
| [cb43451] | 36 | #if 0
 | 
|---|
 | 37 | #define PRINT(x) x
 | 
|---|
 | 38 | #else
 | 
|---|
 | 39 | #define PRINT(x)
 | 
|---|
 | 40 | #endif
 | 
|---|
 | 41 | 
 | 
|---|
| [51b73452] | 42 | namespace GenPoly {
 | 
|---|
| [01aeade] | 43 |         namespace {
 | 
|---|
| [9a34b5a] | 44 |                 // TODO: fold this into the general createDeref function??
 | 
|---|
 | 45 |                 Expression * mkDeref( Expression * arg ) {
 | 
|---|
 | 46 |                         if ( SymTab::dereferenceOperator ) {
 | 
|---|
 | 47 |                                 VariableExpr * deref = new VariableExpr( SymTab::dereferenceOperator );
 | 
|---|
| [0690350] | 48 |                                 deref->result = new PointerType( Type::Qualifiers(), deref->result );
 | 
|---|
 | 49 |                                 Type * base = InitTweak::getPointerBase( arg->result );
 | 
|---|
 | 50 |                                 assertf( base, "expected pointer type in dereference (type was %s)", toString( arg->result ).c_str() );
 | 
|---|
| [9a34b5a] | 51 |                                 ApplicationExpr * ret = new ApplicationExpr( deref, { arg } );
 | 
|---|
| [0690350] | 52 |                                 delete ret->result;
 | 
|---|
 | 53 |                                 ret->result = base->clone();
 | 
|---|
 | 54 |                                 ret->result->set_lvalue( true );
 | 
|---|
| [9a34b5a] | 55 |                                 return ret;
 | 
|---|
 | 56 |                         } else {
 | 
|---|
 | 57 |                                 return UntypedExpr::createDeref( arg );
 | 
|---|
 | 58 |                         }
 | 
|---|
 | 59 |                 }
 | 
|---|
 | 60 | 
 | 
|---|
| [1d776fd] | 61 |                 struct ReferenceConversions final {
 | 
|---|
 | 62 |                         Expression * postmutate( CastExpr * castExpr );
 | 
|---|
| [8a6cf7e] | 63 |                         Expression * postmutate( AddressExpr * addrExpr );
 | 
|---|
| [01aeade] | 64 |                 };
 | 
|---|
 | 65 | 
 | 
|---|
| [1d776fd] | 66 |                 /// Intrinsic functions that take reference parameters don't REALLY take reference parameters -- their reference arguments must always be implicitly dereferenced.
 | 
|---|
 | 67 |                 struct FixIntrinsicArgs final {
 | 
|---|
| [8499c707] | 68 |                         Expression * postmutate( ApplicationExpr * appExpr );
 | 
|---|
| [1d776fd] | 69 |                 };
 | 
|---|
 | 70 | 
 | 
|---|
| [9aaac6e9] | 71 |                 struct FixIntrinsicResult final : public WithGuards {
 | 
|---|
| [8499c707] | 72 |                         Expression * postmutate( ApplicationExpr * appExpr );
 | 
|---|
| [9aaac6e9] | 73 |                         void premutate( FunctionDecl * funcDecl );
 | 
|---|
 | 74 |                         bool inIntrinsic = false;
 | 
|---|
| [8499c707] | 75 |                 };
 | 
|---|
| [1d776fd] | 76 | 
 | 
|---|
 | 77 |                 /// Replace reference types with pointer types
 | 
|---|
 | 78 |                 struct ReferenceTypeElimination final {
 | 
|---|
 | 79 |                         Type * postmutate( ReferenceType * refType );
 | 
|---|
| [01aeade] | 80 |                 };
 | 
|---|
| [b6fd751] | 81 | 
 | 
|---|
 | 82 |                 /// GCC-like Generalized Lvalues (which have since been removed from GCC)
 | 
|---|
 | 83 |                 /// https://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Lvalues.html#Lvalues
 | 
|---|
 | 84 |                 /// Replaces &(a,b) with (a, &b), &(a ? b : c) with (a ? &b : &c)
 | 
|---|
| [d335627] | 85 |                 struct GeneralizedLvalue final : public WithVisitorRef<GeneralizedLvalue> {
 | 
|---|
| [1d776fd] | 86 |                         Expression * postmutate( AddressExpr * addressExpr );
 | 
|---|
| [9236060] | 87 |                         Expression * postmutate( MemberExpr * memExpr );
 | 
|---|
| [acd7c5dd] | 88 | 
 | 
|---|
 | 89 |                         template<typename Func>
 | 
|---|
 | 90 |                         Expression * applyTransformation( Expression * expr, Expression * arg, Func mkExpr );
 | 
|---|
| [b6fd751] | 91 |                 };
 | 
|---|
| [cb43451] | 92 | 
 | 
|---|
 | 93 |                 /// Removes redundant &*/*& pattern that this pass can generate
 | 
|---|
 | 94 |                 struct CollapseAddrDeref final {
 | 
|---|
 | 95 |                         Expression * postmutate( AddressExpr * addressExpr );
 | 
|---|
 | 96 |                         Expression * postmutate( ApplicationExpr * appExpr );
 | 
|---|
 | 97 |                 };
 | 
|---|
| [8499c707] | 98 | 
 | 
|---|
 | 99 |                 struct AddrRef final : public WithGuards {
 | 
|---|
 | 100 |                         void premutate( AddressExpr * addrExpr );
 | 
|---|
 | 101 |                         Expression * postmutate( AddressExpr * addrExpr );
 | 
|---|
 | 102 |                         void premutate( Expression * expr );
 | 
|---|
 | 103 | 
 | 
|---|
 | 104 |                         bool first = true;
 | 
|---|
 | 105 |                         bool current = false;
 | 
|---|
 | 106 |                         int refDepth = 0;
 | 
|---|
 | 107 |                 };
 | 
|---|
| [01aeade] | 108 |         } // namespace
 | 
|---|
 | 109 | 
 | 
|---|
| [b0440b7] | 110 |         static bool referencesEliminated = false;
 | 
|---|
 | 111 |         // used by UntypedExpr::createDeref to determine whether result type of dereference should be ReferenceType or value type.
 | 
|---|
 | 112 |         bool referencesPermissable() {
 | 
|---|
 | 113 |                 return ! referencesEliminated;
 | 
|---|
 | 114 |         }
 | 
|---|
 | 115 | 
 | 
|---|
| [01aeade] | 116 |         void convertLvalue( std::list< Declaration* >& translationUnit ) {
 | 
|---|
| [1d776fd] | 117 |                 PassVisitor<ReferenceConversions> refCvt;
 | 
|---|
 | 118 |                 PassVisitor<ReferenceTypeElimination> elim;
 | 
|---|
 | 119 |                 PassVisitor<GeneralizedLvalue> genLval;
 | 
|---|
 | 120 |                 PassVisitor<FixIntrinsicArgs> fixer;
 | 
|---|
| [cb43451] | 121 |                 PassVisitor<CollapseAddrDeref> collapser;
 | 
|---|
| [8499c707] | 122 |                 PassVisitor<AddrRef> addrRef;
 | 
|---|
 | 123 |                 PassVisitor<FixIntrinsicResult> intrinsicResults;
 | 
|---|
 | 124 |                 mutateAll( translationUnit, intrinsicResults );
 | 
|---|
 | 125 |                 mutateAll( translationUnit, addrRef );
 | 
|---|
| [1d776fd] | 126 |                 mutateAll( translationUnit, refCvt );
 | 
|---|
 | 127 |                 mutateAll( translationUnit, fixer );
 | 
|---|
| [cb43451] | 128 |                 mutateAll( translationUnit, collapser );
 | 
|---|
| [8499c707] | 129 |                 mutateAll( translationUnit, genLval );
 | 
|---|
| [8a6cf7e] | 130 |                 mutateAll( translationUnit, elim );  // last because other passes need reference types to work
 | 
|---|
| [b0440b7] | 131 | 
 | 
|---|
 | 132 |                 // from this point forward, no other pass should create reference types.
 | 
|---|
 | 133 |                 referencesEliminated = true;
 | 
|---|
| [01aeade] | 134 |         }
 | 
|---|
 | 135 | 
 | 
|---|
| [acd7c5dd] | 136 |         Expression * generalizedLvalue( Expression * expr ) {
 | 
|---|
| [9236060] | 137 |                 PassVisitor<GeneralizedLvalue> genLval;
 | 
|---|
| [acd7c5dd] | 138 |                 return expr->acceptMutator( genLval );
 | 
|---|
 | 139 |         }
 | 
|---|
 | 140 | 
 | 
|---|
| [01aeade] | 141 |         namespace {
 | 
|---|
| [8a6cf7e] | 142 |                 // true for intrinsic function calls that return a reference
 | 
|---|
| [1d776fd] | 143 |                 bool isIntrinsicReference( Expression * expr ) {
 | 
|---|
| [8a6cf7e] | 144 |                         if ( UntypedExpr * untyped = dynamic_cast< UntypedExpr * >( expr ) ) {
 | 
|---|
 | 145 |                                 std::string fname = InitTweak::getFunctionName( untyped );
 | 
|---|
 | 146 |                                 // known intrinsic-reference prelude functions
 | 
|---|
 | 147 |                                 return fname == "*?" || fname == "?[?]";
 | 
|---|
| [1d776fd] | 148 |                         } else if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * > ( expr ) ) {
 | 
|---|
 | 149 |                                 if ( DeclarationWithType * func = InitTweak::getFunction( appExpr ) ) {
 | 
|---|
| [8a6cf7e] | 150 |                                         // use type of return variable rather than expr result type, since it may have been changed to a pointer type
 | 
|---|
 | 151 |                                         FunctionType * ftype = GenPoly::getFunctionType( func->get_type() );
 | 
|---|
 | 152 |                                         Type * ret = ftype->get_returnVals().empty() ? nullptr : ftype->get_returnVals().front()->get_type();
 | 
|---|
 | 153 |                                         return func->get_linkage() == LinkageSpec::Intrinsic && dynamic_cast<ReferenceType *>( ret );
 | 
|---|
| [1d776fd] | 154 |                                 }
 | 
|---|
| [ce8c12f] | 155 |                         }
 | 
|---|
| [1d776fd] | 156 |                         return false;
 | 
|---|
| [ce8c12f] | 157 |                 }
 | 
|---|
 | 158 | 
 | 
|---|
| [8499c707] | 159 |                 Expression * FixIntrinsicResult::postmutate( ApplicationExpr * appExpr ) {
 | 
|---|
 | 160 |                         if ( isIntrinsicReference( appExpr ) ) {
 | 
|---|
 | 161 |                                 // eliminate reference types from intrinsic applications - now they return lvalues
 | 
|---|
 | 162 |                                 Type * result = appExpr->get_result();
 | 
|---|
 | 163 |                                 appExpr->set_result( result->stripReferences()->clone() );
 | 
|---|
 | 164 |                                 appExpr->get_result()->set_lvalue( true );
 | 
|---|
| [9aaac6e9] | 165 |                                 if ( ! inIntrinsic ) {
 | 
|---|
 | 166 |                                         // when not in an intrinsic function, add a cast to
 | 
|---|
 | 167 |                                         // don't add cast when in an intrinsic function, since they already have the cast
 | 
|---|
 | 168 |                                         Expression * ret = new CastExpr( appExpr, result );
 | 
|---|
 | 169 |                                         ret->set_env( appExpr->get_env() );
 | 
|---|
 | 170 |                                         appExpr->set_env( nullptr );
 | 
|---|
 | 171 |                                         return ret;
 | 
|---|
 | 172 |                                 }
 | 
|---|
 | 173 |                                 delete result;
 | 
|---|
| [8499c707] | 174 |                         }
 | 
|---|
 | 175 |                         return appExpr;
 | 
|---|
 | 176 |                 }
 | 
|---|
 | 177 | 
 | 
|---|
| [9aaac6e9] | 178 |                 void FixIntrinsicResult::premutate( FunctionDecl * funcDecl ) {
 | 
|---|
 | 179 |                         GuardValue( inIntrinsic );
 | 
|---|
 | 180 |                         inIntrinsic =  funcDecl->linkage == LinkageSpec::Intrinsic;
 | 
|---|
 | 181 |                 }
 | 
|---|
 | 182 | 
 | 
|---|
| [1d776fd] | 183 |                 Expression * FixIntrinsicArgs::postmutate( ApplicationExpr * appExpr ) {
 | 
|---|
| [9a34b5a] | 184 |                         // intrinsic functions don't really take reference-typed parameters, so they require an implicit dereference on their arguments.
 | 
|---|
| [1d776fd] | 185 |                         if ( DeclarationWithType * function = InitTweak::getFunction( appExpr ) ) {
 | 
|---|
| [d335627] | 186 |                                 FunctionType * ftype = GenPoly::getFunctionType( function->get_type() );
 | 
|---|
 | 187 |                                 assertf( ftype, "Function declaration does not have function type." );
 | 
|---|
 | 188 |                                 // can be of differing lengths only when function is variadic
 | 
|---|
 | 189 |                                 assertf( ftype->get_parameters().size() == appExpr->get_args().size() || ftype->get_isVarArgs(), "ApplicationExpr args do not match formal parameter type." );
 | 
|---|
| [b0440b7] | 190 | 
 | 
|---|
 | 191 | 
 | 
|---|
| [d335627] | 192 |                                 unsigned int i = 0;
 | 
|---|
 | 193 |                                 const unsigned int end = ftype->get_parameters().size();
 | 
|---|
 | 194 |                                 for ( auto p : unsafe_group_iterate( appExpr->get_args(), ftype->get_parameters() ) ) {
 | 
|---|
 | 195 |                                         if (i == end) break;
 | 
|---|
 | 196 |                                         Expression *& arg = std::get<0>( p );
 | 
|---|
 | 197 |                                         Type * formal = std::get<1>( p )->get_type();
 | 
|---|
 | 198 |                                         PRINT(
 | 
|---|
 | 199 |                                                 std::cerr << "pair<0>: " << arg << std::endl;
 | 
|---|
 | 200 |                                                 std::cerr << "pair<1>: " << formal << std::endl;
 | 
|---|
 | 201 |                                         )
 | 
|---|
 | 202 |                                         if ( dynamic_cast<ReferenceType*>( formal ) ) {
 | 
|---|
| [8499c707] | 203 |                                                 if ( isIntrinsicReference( arg ) ) { // do not combine conditions, because that changes the meaning of the else if
 | 
|---|
| [d335627] | 204 |                                                         if ( function->get_linkage() != LinkageSpec::Intrinsic ) { // intrinsic functions that turn pointers into references
 | 
|---|
 | 205 |                                                                 // if argument is dereference or array subscript, the result isn't REALLY a reference, so it's not necessary to fix the argument
 | 
|---|
| [8499c707] | 206 |                                                                 PRINT(
 | 
|---|
 | 207 |                                                                         std::cerr << "===is intrinsic arg in non-intrinsic call - adding address" << std::endl;
 | 
|---|
 | 208 |                                                                 )
 | 
|---|
| [d335627] | 209 |                                                                 arg = new AddressExpr( arg );
 | 
|---|
 | 210 |                                                         }
 | 
|---|
 | 211 |                                                 } else if ( function->get_linkage() == LinkageSpec::Intrinsic ) {
 | 
|---|
| [8499c707] | 212 |                                                         // std::cerr << "===adding deref to arg" << std::endl;
 | 
|---|
| [d335627] | 213 |                                                         // if the parameter is a reference, add a dereference to the reference-typed argument.
 | 
|---|
 | 214 |                                                         Type * baseType = InitTweak::getPointerBase( arg->get_result() );
 | 
|---|
| [8499c707] | 215 |                                                         assertf( baseType, "parameter is reference, arg must be pointer or reference: %s", toString( arg->get_result() ).c_str() );
 | 
|---|
| [d335627] | 216 |                                                         PointerType * ptrType = new PointerType( Type::Qualifiers(), baseType->clone() );
 | 
|---|
 | 217 |                                                         delete arg->get_result();
 | 
|---|
 | 218 |                                                         arg->set_result( ptrType );
 | 
|---|
 | 219 |                                                         arg = mkDeref( arg );
 | 
|---|
| [1d776fd] | 220 |                                                 }
 | 
|---|
 | 221 |                                         }
 | 
|---|
| [d335627] | 222 |                                         ++i;
 | 
|---|
| [baba5d8] | 223 |                                 }
 | 
|---|
| [1d776fd] | 224 |                         }
 | 
|---|
 | 225 |                         return appExpr;
 | 
|---|
| [01aeade] | 226 |                 }
 | 
|---|
 | 227 | 
 | 
|---|
| [8499c707] | 228 |                 // idea: &&&E: get outer &, inner &
 | 
|---|
 | 229 |                 // at inner &, record depth D of reference type
 | 
|---|
 | 230 |                 // at outer &, add D derefs.
 | 
|---|
| [8135d4c] | 231 |                 void AddrRef::premutate( Expression * ) {
 | 
|---|
| [8499c707] | 232 |                         GuardValue( current );
 | 
|---|
 | 233 |                         GuardValue( first );
 | 
|---|
 | 234 |                         current = false;
 | 
|---|
 | 235 |                         first = true;
 | 
|---|
 | 236 |                 }
 | 
|---|
 | 237 | 
 | 
|---|
| [8135d4c] | 238 |                 void AddrRef::premutate( AddressExpr * ) {
 | 
|---|
| [8499c707] | 239 |                         GuardValue( current );
 | 
|---|
 | 240 |                         GuardValue( first );
 | 
|---|
 | 241 |                         current = first;
 | 
|---|
 | 242 |                         first = false;
 | 
|---|
 | 243 |                         if ( current ) {
 | 
|---|
 | 244 |                                 GuardValue( refDepth );
 | 
|---|
 | 245 |                                 refDepth = 0;
 | 
|---|
 | 246 |                         }
 | 
|---|
 | 247 |                 }
 | 
|---|
 | 248 | 
 | 
|---|
 | 249 |                 Expression * AddrRef::postmutate( AddressExpr * addrExpr ) {
 | 
|---|
 | 250 |                         if ( refDepth == 0 ) {
 | 
|---|
 | 251 |                                 if ( ! isIntrinsicReference( addrExpr->get_arg() ) ) {
 | 
|---|
 | 252 |                                         // try to avoid ?[?]
 | 
|---|
 | 253 |                                         refDepth = addrExpr->get_arg()->get_result()->referenceDepth();
 | 
|---|
 | 254 |                                 }
 | 
|---|
 | 255 |                         }
 | 
|---|
 | 256 |                         if ( current ) {
 | 
|---|
 | 257 |                                 Expression * ret = addrExpr;
 | 
|---|
 | 258 |                                 while ( refDepth ) {
 | 
|---|
 | 259 |                                         ret = mkDeref( ret );
 | 
|---|
 | 260 |                                         refDepth--;
 | 
|---|
 | 261 |                                 }
 | 
|---|
 | 262 |                                 return ret;
 | 
|---|
 | 263 |                         }
 | 
|---|
 | 264 |                         return addrExpr;
 | 
|---|
 | 265 |                 }
 | 
|---|
 | 266 | 
 | 
|---|
| [8a6cf7e] | 267 |                 Expression * ReferenceConversions::postmutate( AddressExpr * addrExpr ) {
 | 
|---|
 | 268 |                         // Inner expression may have been lvalue to reference conversion, which becomes an address expression.
 | 
|---|
 | 269 |                         // In this case, remove the outer address expression and return the argument.
 | 
|---|
 | 270 |                         // TODO: It's possible that this might catch too much and require a more sophisticated check.
 | 
|---|
 | 271 |                         return addrExpr;
 | 
|---|
 | 272 |                 }
 | 
|---|
 | 273 | 
 | 
|---|
| [1d776fd] | 274 |                 Expression * ReferenceConversions::postmutate( CastExpr * castExpr ) {
 | 
|---|
| [9a34b5a] | 275 |                         // xxx - is it possible to convert directly between reference types with a different base? E.g.,
 | 
|---|
 | 276 |                         //   int x;
 | 
|---|
 | 277 |                         //   (double&)x;
 | 
|---|
 | 278 |                         // At the moment, I am working off of the assumption that this is illegal, thus the cast becomes redundant
 | 
|---|
 | 279 |                         // after this pass, so trash the cast altogether. If that changes, care must be taken to insert the correct
 | 
|---|
 | 280 |                         // pointer casts in the right places.
 | 
|---|
 | 281 | 
 | 
|---|
| [1d776fd] | 282 |                         // conversion to reference type
 | 
|---|
 | 283 |                         if ( ReferenceType * refType = dynamic_cast< ReferenceType * >( castExpr->get_result() ) ) {
 | 
|---|
 | 284 |                                 (void)refType;
 | 
|---|
 | 285 |                                 if ( ReferenceType * otherRef = dynamic_cast< ReferenceType * >( castExpr->get_arg()->get_result() ) ) {
 | 
|---|
 | 286 |                                         // nothing to do if casting from reference to reference.
 | 
|---|
 | 287 |                                         (void)otherRef;
 | 
|---|
| [cb43451] | 288 |                                         PRINT( std::cerr << "convert reference to reference -- nop" << std::endl; )
 | 
|---|
| [1d776fd] | 289 |                                         if ( isIntrinsicReference( castExpr->get_arg() ) ) {
 | 
|---|
 | 290 |                                                 Expression * callExpr = castExpr->get_arg();
 | 
|---|
| [cb43451] | 291 |                                                 PRINT(
 | 
|---|
 | 292 |                                                         std::cerr << "but arg is deref -- &" << std::endl;
 | 
|---|
 | 293 |                                                         std::cerr << callExpr << std::endl;
 | 
|---|
 | 294 |                                                 )
 | 
|---|
| [8499c707] | 295 |                                                 callExpr = new AddressExpr( callExpr ); // this doesn't work properly for multiple casts
 | 
|---|
 | 296 |                                                 delete callExpr->get_result();
 | 
|---|
 | 297 |                                                 callExpr->set_result( refType->clone() );
 | 
|---|
| [1d776fd] | 298 |                                                 // move environment out to new top-level
 | 
|---|
 | 299 |                                                 callExpr->set_env( castExpr->get_env() );
 | 
|---|
| [9a34b5a] | 300 |                                                 castExpr->set_arg( nullptr );
 | 
|---|
| [1d776fd] | 301 |                                                 castExpr->set_env( nullptr );
 | 
|---|
| [9a34b5a] | 302 |                                                 delete castExpr;
 | 
|---|
| [1d776fd] | 303 |                                                 return callExpr;
 | 
|---|
 | 304 |                                         }
 | 
|---|
| [8499c707] | 305 |                                         int depth1 = refType->referenceDepth();
 | 
|---|
 | 306 |                                         int depth2 = otherRef->referenceDepth();
 | 
|---|
| [fc56cdbf] | 307 |                                         int diff = depth1-depth2;
 | 
|---|
 | 308 |                                         if ( diff == 0 ) {
 | 
|---|
| [0690350] | 309 |                                                 // conversion between references of the same depth
 | 
|---|
| [fc56cdbf] | 310 |                                                 assertf( depth1 == depth2, "non-intrinsic reference with cast of reference to reference not yet supported: %d %d %s", depth1, depth2, toString( castExpr ).c_str() );
 | 
|---|
 | 311 |                                                 PRINT( std::cerr << castExpr << std::endl; )
 | 
|---|
 | 312 |                                                 return castExpr;
 | 
|---|
 | 313 |                                         } else if ( diff < 0 ) {
 | 
|---|
| [0690350] | 314 |                                                 // conversion from reference to reference with less depth (e.g. int && -> int &): add dereferences
 | 
|---|
 | 315 |                                                 Expression * ret = castExpr->arg;
 | 
|---|
| [fc56cdbf] | 316 |                                                 for ( int i = 0; i < diff; ++i ) {
 | 
|---|
 | 317 |                                                         ret = mkDeref( ret );
 | 
|---|
 | 318 |                                                 }
 | 
|---|
| [0690350] | 319 |                                                 ret->env = castExpr->env;
 | 
|---|
 | 320 |                                                 delete ret->result;
 | 
|---|
 | 321 |                                                 ret->result = castExpr->result;
 | 
|---|
| [1a4bef3] | 322 |                                                 ret->result->set_lvalue( true ); // ensure result is lvalue
 | 
|---|
| [0690350] | 323 |                                                 castExpr->env = nullptr;
 | 
|---|
 | 324 |                                                 castExpr->arg = nullptr;
 | 
|---|
 | 325 |                                                 castExpr->result = nullptr;
 | 
|---|
| [fc56cdbf] | 326 |                                                 delete castExpr;
 | 
|---|
 | 327 |                                                 return ret;
 | 
|---|
 | 328 |                                         } else if ( diff > 0 ) {
 | 
|---|
| [0690350] | 329 |                                                 // conversion from reference to reference with more depth (e.g. int & -> int &&): add address-of
 | 
|---|
 | 330 |                                                 Expression * ret = castExpr->arg;
 | 
|---|
| [fc56cdbf] | 331 |                                                 for ( int i = 0; i < diff; ++i ) {
 | 
|---|
 | 332 |                                                         ret = new AddressExpr( ret );
 | 
|---|
 | 333 |                                                 }
 | 
|---|
| [0690350] | 334 |                                                 ret->env = castExpr->env;
 | 
|---|
 | 335 |                                                 delete ret->result;
 | 
|---|
 | 336 |                                                 ret->result = castExpr->result;
 | 
|---|
 | 337 |                                                 castExpr->env = nullptr;
 | 
|---|
 | 338 |                                                 castExpr->arg = nullptr;
 | 
|---|
 | 339 |                                                 castExpr->result = nullptr;
 | 
|---|
| [fc56cdbf] | 340 |                                                 delete castExpr;
 | 
|---|
 | 341 |                                                 return ret;
 | 
|---|
 | 342 |                                         }
 | 
|---|
 | 343 | 
 | 
|---|
| [8499c707] | 344 |                                         assertf( depth1 == depth2, "non-intrinsic reference with cast of reference to reference not yet supported: %d %d %s", depth1, depth2, toString( castExpr ).c_str() );
 | 
|---|
| [cb43451] | 345 |                                         PRINT( std::cerr << castExpr << std::endl; )
 | 
|---|
| [1d776fd] | 346 |                                         return castExpr;
 | 
|---|
| [0690350] | 347 |                                 } else if ( castExpr->arg->result->get_lvalue() ) {
 | 
|---|
| [1d776fd] | 348 |                                         // conversion from lvalue to reference
 | 
|---|
 | 349 |                                         // xxx - keep cast, but turn into pointer cast??
 | 
|---|
 | 350 |                                         // xxx - memory
 | 
|---|
| [cb43451] | 351 |                                         PRINT(
 | 
|---|
 | 352 |                                                 std::cerr << "convert lvalue to reference -- &" << std::endl;
 | 
|---|
| [0690350] | 353 |                                                 std::cerr << castExpr->arg << std::endl;
 | 
|---|
| [cb43451] | 354 |                                         )
 | 
|---|
| [0690350] | 355 |                                         AddressExpr * ret = new AddressExpr( castExpr->arg );
 | 
|---|
 | 356 |                                         if ( refType->base->get_qualifiers() != castExpr->arg->result->get_qualifiers() ) {
 | 
|---|
| [cb43451] | 357 |                                                 // must keep cast if cast-to type is different from the actual type
 | 
|---|
| [0690350] | 358 |                                                 castExpr->arg = ret;
 | 
|---|
| [cb43451] | 359 |                                                 return castExpr;
 | 
|---|
 | 360 |                                         }
 | 
|---|
| [0690350] | 361 |                                         ret->env = castExpr->env;
 | 
|---|
 | 362 |                                         delete ret->result;
 | 
|---|
 | 363 |                                         ret->result = castExpr->result;
 | 
|---|
 | 364 |                                         castExpr->env = nullptr;
 | 
|---|
 | 365 |                                         castExpr->arg = nullptr;
 | 
|---|
 | 366 |                                         castExpr->result = nullptr;
 | 
|---|
| [9a34b5a] | 367 |                                         delete castExpr;
 | 
|---|
 | 368 |                                         return ret;
 | 
|---|
| [01aeade] | 369 |                                 } else {
 | 
|---|
| [1d776fd] | 370 |                                         // rvalue to reference conversion -- introduce temporary
 | 
|---|
 | 371 |                                 }
 | 
|---|
 | 372 |                                 assertf( false, "Only conversions to reference from lvalue are currently supported: %s", toString( castExpr ).c_str() );
 | 
|---|
| [0690350] | 373 |                         } else if ( ReferenceType * refType = dynamic_cast< ReferenceType * >( castExpr->arg->result ) ) {
 | 
|---|
| [d335627] | 374 |                                 (void)refType;
 | 
|---|
| [9a34b5a] | 375 |                                 // conversion from reference to rvalue
 | 
|---|
| [8a6cf7e] | 376 |                                 PRINT(
 | 
|---|
 | 377 |                                         std::cerr << "convert reference to rvalue -- *" << std::endl;
 | 
|---|
 | 378 |                                         std::cerr << "was = " << castExpr << std::endl;
 | 
|---|
 | 379 |                                 )
 | 
|---|
| [0690350] | 380 |                                 Expression * ret = castExpr->arg;
 | 
|---|
 | 381 |                                 TypeSubstitution * env = castExpr->env;
 | 
|---|
| [8a6cf7e] | 382 |                                 castExpr->set_env( nullptr );
 | 
|---|
| [9191a8e] | 383 |                                 if ( ! isIntrinsicReference( ret ) ) {
 | 
|---|
 | 384 |                                         // dereference if not already dereferenced
 | 
|---|
 | 385 |                                         ret = mkDeref( ret );
 | 
|---|
 | 386 |                                 }
 | 
|---|
| [0690350] | 387 |                                 if ( ResolvExpr::typesCompatibleIgnoreQualifiers( castExpr->result, castExpr->arg->result->stripReferences(), SymTab::Indexer() ) ) {
 | 
|---|
| [b0440b7] | 388 |                                         // can remove cast if types are compatible, changing expression type to value type
 | 
|---|
| [0690350] | 389 |                                         ret->result = castExpr->result->clone();
 | 
|---|
| [1a4bef3] | 390 |                                         ret->result->set_lvalue( true );  // ensure result is lvalue
 | 
|---|
| [0690350] | 391 |                                         castExpr->arg = nullptr;
 | 
|---|
| [8a6cf7e] | 392 |                                         delete castExpr;
 | 
|---|
 | 393 |                                 } else {
 | 
|---|
 | 394 |                                         // must keep cast if types are different
 | 
|---|
| [0690350] | 395 |                                         castExpr->arg = ret;
 | 
|---|
| [8a6cf7e] | 396 |                                         ret = castExpr;
 | 
|---|
 | 397 |                                 }
 | 
|---|
 | 398 |                                 ret->set_env( env );
 | 
|---|
| [9191a8e] | 399 |                                 PRINT( std::cerr << "now: " << ret << std::endl; )
 | 
|---|
 | 400 |                                 return ret;
 | 
|---|
| [1d776fd] | 401 |                         }
 | 
|---|
 | 402 |                         return castExpr;
 | 
|---|
| [01aeade] | 403 |                 }
 | 
|---|
| [b6fd751] | 404 | 
 | 
|---|
| [1d776fd] | 405 |                 Type * ReferenceTypeElimination::postmutate( ReferenceType * refType ) {
 | 
|---|
 | 406 |                         Type * base = refType->get_base();
 | 
|---|
| [8a6cf7e] | 407 |                         Type::Qualifiers qualifiers = refType->get_qualifiers();
 | 
|---|
| [1d776fd] | 408 |                         refType->set_base( nullptr );
 | 
|---|
 | 409 |                         delete refType;
 | 
|---|
| [8a6cf7e] | 410 |                         return new PointerType( qualifiers, base );
 | 
|---|
| [ce8c12f] | 411 |                 }
 | 
|---|
 | 412 | 
 | 
|---|
| [acd7c5dd] | 413 |                 template<typename Func>
 | 
|---|
 | 414 |                 Expression * GeneralizedLvalue::applyTransformation( Expression * expr, Expression * arg, Func mkExpr ) {
 | 
|---|
 | 415 |                         if ( CommaExpr * commaExpr = dynamic_cast< CommaExpr * >( arg ) ) {
 | 
|---|
| [b6fd751] | 416 |                                 Expression * arg1 = commaExpr->get_arg1()->clone();
 | 
|---|
 | 417 |                                 Expression * arg2 = commaExpr->get_arg2()->clone();
 | 
|---|
| [9236060] | 418 |                                 Expression * ret = new CommaExpr( arg1, mkExpr( arg2 )->acceptMutator( *visitor ) );
 | 
|---|
| [acd7c5dd] | 419 |                                 ret->set_env( expr->get_env() );
 | 
|---|
 | 420 |                                 expr->set_env( nullptr );
 | 
|---|
 | 421 |                                 delete expr;
 | 
|---|
| [8499c707] | 422 |                                 return ret;
 | 
|---|
| [acd7c5dd] | 423 |                         } else if ( ConditionalExpr * condExpr = dynamic_cast< ConditionalExpr * >( arg ) ) {
 | 
|---|
| [b6fd751] | 424 |                                 Expression * arg1 = condExpr->get_arg1()->clone();
 | 
|---|
 | 425 |                                 Expression * arg2 = condExpr->get_arg2()->clone();
 | 
|---|
 | 426 |                                 Expression * arg3 = condExpr->get_arg3()->clone();
 | 
|---|
| [9236060] | 427 |                                 ConditionalExpr * ret = new ConditionalExpr( arg1, mkExpr( arg2 )->acceptMutator( *visitor ), mkExpr( arg3 )->acceptMutator( *visitor ) );
 | 
|---|
| [acd7c5dd] | 428 |                                 ret->set_env( expr->get_env() );
 | 
|---|
 | 429 |                                 expr->set_env( nullptr );
 | 
|---|
 | 430 |                                 delete expr;
 | 
|---|
 | 431 | 
 | 
|---|
 | 432 |                                 // conditional expr type may not be either of the argument types, need to unify
 | 
|---|
 | 433 |                                 using namespace ResolvExpr;
 | 
|---|
 | 434 |                                 Type* commonType = nullptr;
 | 
|---|
 | 435 |                                 TypeEnvironment newEnv;
 | 
|---|
 | 436 |                                 AssertionSet needAssertions, haveAssertions;
 | 
|---|
 | 437 |                                 OpenVarSet openVars;
 | 
|---|
 | 438 |                                 unify( ret->get_arg2()->get_result(), ret->get_arg3()->get_result(), newEnv, needAssertions, haveAssertions, openVars, SymTab::Indexer(), commonType );
 | 
|---|
 | 439 |                                 ret->set_result( commonType ? commonType : ret->get_arg2()->get_result()->clone() );
 | 
|---|
| [8499c707] | 440 |                                 return ret;
 | 
|---|
| [b6fd751] | 441 |                         }
 | 
|---|
| [acd7c5dd] | 442 |                         return expr;
 | 
|---|
 | 443 |                 }
 | 
|---|
 | 444 | 
 | 
|---|
| [9236060] | 445 |                 Expression * GeneralizedLvalue::postmutate( MemberExpr * memExpr ) {
 | 
|---|
| [acd7c5dd] | 446 |                         return applyTransformation( memExpr, memExpr->get_aggregate(), [=]( Expression * aggr ) { return new MemberExpr( memExpr->get_member(), aggr ); } );
 | 
|---|
 | 447 |                 }
 | 
|---|
 | 448 | 
 | 
|---|
| [9236060] | 449 |                 Expression * GeneralizedLvalue::postmutate( AddressExpr * addrExpr ) {
 | 
|---|
| [acd7c5dd] | 450 |                         return applyTransformation( addrExpr, addrExpr->get_arg(), []( Expression * arg ) { return new AddressExpr( arg ); } );
 | 
|---|
| [b6fd751] | 451 |                 }
 | 
|---|
| [cb43451] | 452 | 
 | 
|---|
| [8499c707] | 453 |                 Expression * CollapseAddrDeref::postmutate( AddressExpr * addrExpr ) {
 | 
|---|
 | 454 |                         Expression * arg = addrExpr->get_arg();
 | 
|---|
| [cb43451] | 455 |                         if ( isIntrinsicReference( arg ) ) {
 | 
|---|
 | 456 |                                 std::string fname = InitTweak::getFunctionName( arg );
 | 
|---|
 | 457 |                                 if ( fname == "*?" ) {
 | 
|---|
 | 458 |                                         Expression *& arg0 = InitTweak::getCallArg( arg, 0 );
 | 
|---|
 | 459 |                                         Expression * ret = arg0;
 | 
|---|
| [8499c707] | 460 |                                         ret->set_env( addrExpr->get_env() );
 | 
|---|
| [cb43451] | 461 |                                         arg0 = nullptr;
 | 
|---|
| [8499c707] | 462 |                                         addrExpr->set_env( nullptr );
 | 
|---|
 | 463 |                                         delete addrExpr;
 | 
|---|
| [cb43451] | 464 |                                         return ret;
 | 
|---|
 | 465 |                                 }
 | 
|---|
| [bf7b6015] | 466 |                         } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * > ( arg ) ) {
 | 
|---|
 | 467 |                                 // need to move cast to pointer type out a level since address of pointer
 | 
|---|
 | 468 |                                 // is not valid C code (can be introduced in prior passes, e.g., InstantiateGeneric)
 | 
|---|
 | 469 |                                 if ( InitTweak::getPointerBase( castExpr->result ) ) {
 | 
|---|
 | 470 |                                         addrExpr->arg = castExpr->arg;
 | 
|---|
 | 471 |                                         castExpr->arg = addrExpr;
 | 
|---|
 | 472 |                                         castExpr->result = new PointerType( Type::Qualifiers(), castExpr->result );
 | 
|---|
 | 473 |                                         return castExpr;
 | 
|---|
 | 474 |                                 }
 | 
|---|
| [cb43451] | 475 |                         }
 | 
|---|
| [8499c707] | 476 |                         return addrExpr;
 | 
|---|
| [cb43451] | 477 |                 }
 | 
|---|
 | 478 | 
 | 
|---|
 | 479 |                 Expression * CollapseAddrDeref::postmutate( ApplicationExpr * appExpr ) {
 | 
|---|
 | 480 |                         if ( isIntrinsicReference( appExpr ) ) {
 | 
|---|
 | 481 |                                 std::string fname = InitTweak::getFunctionName( appExpr );
 | 
|---|
 | 482 |                                 if ( fname == "*?" ) {
 | 
|---|
 | 483 |                                         Expression * arg = InitTweak::getCallArg( appExpr, 0 );
 | 
|---|
 | 484 |                                         // xxx - this isn't right, because it can remove casts that should be there...
 | 
|---|
 | 485 |                                         // while ( CastExpr * castExpr = dynamic_cast< CastExpr * >( arg ) ) {
 | 
|---|
 | 486 |                                         //      arg = castExpr->get_arg();
 | 
|---|
 | 487 |                                         // }
 | 
|---|
 | 488 |                                         if ( AddressExpr * addrExpr = dynamic_cast< AddressExpr * >( arg ) ) {
 | 
|---|
 | 489 |                                                 Expression * ret = addrExpr->get_arg();
 | 
|---|
 | 490 |                                                 ret->set_env( appExpr->get_env() );
 | 
|---|
 | 491 |                                                 addrExpr->set_arg( nullptr );
 | 
|---|
 | 492 |                                                 appExpr->set_env( nullptr );
 | 
|---|
 | 493 |                                                 delete appExpr;
 | 
|---|
 | 494 |                                                 return ret;
 | 
|---|
 | 495 |                                         }
 | 
|---|
 | 496 |                                 }
 | 
|---|
 | 497 |                         }
 | 
|---|
 | 498 |                         return appExpr;
 | 
|---|
 | 499 |                 }
 | 
|---|
| [01aeade] | 500 |         } // namespace
 | 
|---|
| [51b73452] | 501 | } // namespace GenPoly
 | 
|---|
| [01aeade] | 502 | 
 | 
|---|
| [51587aa] | 503 | // Local Variables: //
 | 
|---|
 | 504 | // tab-width: 4 //
 | 
|---|
 | 505 | // mode: c++ //
 | 
|---|
 | 506 | // compile-command: "make install" //
 | 
|---|
 | 507 | // End: //
 | 
|---|