source: src/GenPoly/Lvalue.cpp @ 08e0d65

Last change on this file since 08e0d65 was b6f2e7ab, checked in by Andrew Beach <ajbeach@…>, 2 months ago

Removed SizeofExpr::expr and AlignofExpr::expr, expressions that would be stored there are wrapped in TypeofType? and stored in the type field. Some special cases to hide the typeof in code generation were added. In addition, initializer length is calculated in more cases so that the full type of more arrays is known sooner. Other than that, most of the code changes were just stripping out the conditional code and checks no longer needed. Some tests had to be updated, because the typeof is not hidden in dumps and the resolver replaces known typeof expressions with the type. The extension case caused some concern but it appears that just hides warnings in the expression which no longer exists.

  • Property mode set to 100644
File size: 23.5 KB
RevLine 
[7fffb1b]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//
[83fd57d]7// Lvalue.cpp -- Clean up lvalues and remove references.
[7fffb1b]8//
9// Author           : Andrew Beach
10// Created On       : Thu Sep 15 14:08:00 2022
11// Last Modified By : Andrew Beach
[97f8f0f]12// Last Modified On : Mon Aug 12 18:07:00 2024
13// Update Count     : 1
[7fffb1b]14//
15
[c92bdcc]16#include "Lvalue.hpp"
[7fffb1b]17
18#include <set>
19#include <iostream>
20
21#include "AST/Copy.hpp"                // for deepCopy
22#include "AST/Expr.hpp"
23#include "AST/Inspect.hpp"
24#include "AST/LinkageSpec.hpp"         // for Linkage
25#include "AST/Pass.hpp"
[c92bdcc]26#include "Common/SemanticError.hpp"    // for SemanticWarning
[9feb34b]27#include "Common/ToString.hpp"         // for toCString
[c92bdcc]28#include "Common/UniqueName.hpp"       // for UniqueName
29#include "GenPoly/GenPoly.hpp"         // for genFunctionType
30#include "ResolvExpr/Typeops.hpp"      // for typesCompatible
31#include "ResolvExpr/Unify.hpp"        // for unify
[7fffb1b]32
33#if 0
34#define PRINT(x) x
35#else
36#define PRINT(x)
37#endif
38
39namespace GenPoly {
40
41namespace {
42
43/// Intrinsic functions that return references now instead return lvalues.
44struct FixIntrinsicResults final : public ast::WithGuards {
45        enum {
46                NoSkip,
47                Skip,
48                SkipInProgress,
49        } skip = NoSkip;
50
51        void previsit( ast::AsmExpr const * ) {
52                GuardValue( skip ) = Skip;
53        }
54        void previsit( ast::ApplicationExpr const * ) {
55                GuardValue( skip ) = (skip == Skip) ? SkipInProgress : NoSkip;
56        }
57
58        ast::Expr const * postvisit( ast::ApplicationExpr const * expr );
59        void previsit( ast::FunctionDecl const * decl );
60        bool inIntrinsic = false;
61};
62
63/// Add de-references around address-of operations on reference types.
64struct AddressRef final :
65                public ast::WithConstTranslationUnit,
66                public ast::WithGuards,
67                public ast::WithShortCircuiting,
68                public ast::WithVisitorRef<AddressRef> {
69        void previsit( ast::AddressExpr const * expr );
70        ast::Expr const * postvisit( ast::AddressExpr const * expr );
71        void previsit( ast::Expr const * expr );
72        ast::ApplicationExpr const * previsit( ast::ApplicationExpr const * expr );
73        void previsit( ast::SingleInit const * init );
74
75        void handleNonAddr( ast::Expr const * expr );
76
77        bool first = true;
78        bool current = false;
79        bool addCast = false;
80        int refDepth = 0;
81};
82
83/// Handles casts between references and pointers,
84/// creating temporaries for the conversion.
85struct ReferenceConversions final :
86                public ast::WithConstTranslationUnit,
87                public ast::WithGuards, public ast::WithStmtsToAdd<> {
88        ast::Expr const * postvisit( ast::CastExpr const * expr );
89        ast::Expr const * postvisit( ast::AddressExpr const * expr );
90};
91
92/// Intrinsic functions that take reference parameters don't actually do.
93/// Their reference arguments must be implicity dereferenced.
94/// TODO Also appears to contain redundent code with AddressRef
95struct FixIntrinsicArgs final :
96                public ast::WithConstTranslationUnit {
97        ast::Expr const * postvisit( ast::ApplicationExpr const * expr );
98};
99
100/// Removes redundant &* / *& patterns that may be generated.
101struct CollapseAddressDeref final {
102        ast::Expr const * postvisit( ast::AddressExpr const * expr );
103        ast::Expr const * postvisit( ast::ApplicationExpr const * expr );
104};
105
106/// GCC-like Generalized Lvalues (which have since been removed from GCC).
107/// https://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Lvalues.html#Lvalues
108/// Replaces &(a,b) with (a, &b), &(a ? b : c) with (a ? &b : &c)
109struct GeneralizedLvalue final :
110                public ast::WithVisitorRef<GeneralizedLvalue> {
111        ast::Expr const * postvisit( ast::AddressExpr const * expr );
112        ast::Expr const * postvisit( ast::MemberExpr const * expr );
113
114        template<typename Node, typename Func>
115        ast::Expr const * applyTransformation(
116              Node const * expr, ast::ptr<ast::Expr> Node::*field, Func mkExpr );
117};
118
119/// Replace all reference types with pointer types.
120struct ReferenceTypeElimination final {
[97f8f0f]121        ast::SizeofExpr const * previsit( ast::SizeofExpr const * expr );
122        ast::AlignofExpr const * previsit( ast::AlignofExpr const * expr );
[7fffb1b]123        ast::Type const * postvisit( ast::ReferenceType const * type );
124};
125
126/// True for intrinsic function calls that return an lvalue in C.
127bool isIntrinsicReference( ast::Expr const * expr ) {
128        // The known intrinsic-reference prelude functions.
129        static std::set<std::string> const lvalueFunctions = { "*?", "?[?]" };
130        if ( auto untyped = dynamic_cast<ast::UntypedExpr const *>( expr ) ) {
131                std::string fname = ast::getFunctionName( untyped );
132                return lvalueFunctions.count( fname );
133        } else if ( auto app = dynamic_cast<ast::ApplicationExpr const *>( expr ) ) {
134                if ( auto func = ast::getFunction( app ) ) {
135                        return func->linkage == ast::Linkage::Intrinsic
136                                && lvalueFunctions.count( func->name );
137                }
138        }
139        return false;
140}
141
142// A maybe typed variant of the createDeref function (only UntypedExpr).
143ast::Expr * mkDeref(
144                ast::TranslationGlobal const & global, ast::Expr const * arg ) {
145        if ( global.dereference ) {
146                // Note: Reference depth can be arbitrarily deep here,
147                // so peel off the outermost pointer/reference, not just
148                // pointer because they are effecitvely equivalent in this pass
149                ast::VariableExpr * deref = new ast::VariableExpr(
150                        arg->location, global.dereference );
151                deref->result = new ast::PointerType( deref->result );
152                ast::Type const * base = ast::getPointerBase( arg->result );
153                assertf( base, "expected pointer type in dereference (type was %s)", toString( arg->result ).c_str() );
154                ast::ApplicationExpr * ret =
155                        new ast::ApplicationExpr( arg->location, deref, { arg } );
156                ret->result = ast::deepCopy( base );
157                return ret;
158        } else {
159                return ast::UntypedExpr::createDeref( arg->location, arg );
160        }
161}
162
163ast::Expr const * FixIntrinsicResults::postvisit(
164                ast::ApplicationExpr const * expr ) {
[c75b30a]165
[af746cc]166        if ( skip == SkipInProgress || !isIntrinsicReference( expr ) ) {
[7fffb1b]167                return expr;
168        }
169        // Eliminate reference types from intrinsic applications
170        // now they return lvalues.
171        ast::ptr<ast::ReferenceType> result =
172                        expr->result.strict_as<ast::ReferenceType>();
173        expr = ast::mutate_field( expr, &ast::ApplicationExpr::result,
174                        ast::deepCopy( result->base ) );
175        if ( inIntrinsic ) {
176                return expr;
177        }
178        // When not in an intrinsic function, add a cast to don't add cast when
179        // in an intrinsic function, since they already have the cast.
180        auto * ret = new ast::CastExpr( expr->location, expr, result.get() );
181        ret->env = expr->env;
182        return ret;
183}
184
185void FixIntrinsicResults::previsit( ast::FunctionDecl const * decl ) {
186        GuardValue( inIntrinsic ) = decl->linkage == ast::Linkage::Intrinsic;
187}
188
189void AddressRef::previsit( ast::AddressExpr const * ) {
190        // Is this the first address-of in the chain?
191        GuardValue( current ) = first;
192        // Later references will not be for next address-of to be first in chain.
193        GuardValue( first ) = false;
194        // If is the outermost address-of in a chain:
195        if ( current ) {
196                // Set depth to 0 so that postvisit can
197                // find the innermost address-of easily.
198                GuardValue( refDepth ) = 0;
199        }
200}
201
202ast::Expr const * AddressRef::postvisit( ast::AddressExpr const * expr ) {
203        PRINT( std::cerr << "addr ref at " << expr << std::endl; )
204        if ( 0 == refDepth ) {
205                PRINT( std::cerr << "depth 0, get new depth..." << std::endl; )
206                // Is this the innermost address-of in a chain? record depth D.
207                if ( isIntrinsicReference( expr->arg ) ) {
208                        assertf( false, "AddrRef : address-of should not have intrinsic reference argument: %s", toCString( expr->arg )  );
209                } else {
210                        // try to avoid ?[?]
211                        // TODO is this condition still necessary? intrinsicReferences
212                        // should have a cast around them at this point, so I don't think
213                        // this condition ever fires.
214                        refDepth = expr->arg->result->referenceDepth();
215                        PRINT( std::cerr << "arg not intrinsic reference, new depth is: " << refDepth << std::endl; )
216                }
217        }
218        if ( current ) {
219                PRINT( std::cerr << "current, depth is: " << refDepth << std::endl; )
220                ast::Expr const * ret = expr;
221                while ( refDepth ) {
222                        // Add one dereference for each address-of in the chain.
223                        ret = mkDeref( transUnit().global, ret );
224                        --refDepth;
225                }
226
227                // if addrExpr depth is 0, then the result is a pointer because the
228                // arg was depth 1 and not lvalue. This means the dereference result
229                // is not a reference, is lvalue, and one less pointer depth than the
230                // addrExpr. Thus the cast is meaningless.
231                // TODO: One thing to double check is whether it is possible for the
232                // types to differ outside of the single pointer level (i.e. can the
233                // base type of addrExpr differ from the type of addrExpr-arg?). If
234                // so then the cast might need to be added, conditional on a more
235                // sophisticated check.
236                if ( addCast && 0 != expr->result->referenceDepth() ) {
237                        PRINT( std::cerr << "adding cast to " << expr->result << std::endl; )
238                        return new ast::CastExpr( expr->location,
239                                ret, ast::deepCopy( expr->result ) );
240                }
241                return ret;
242        }
243        PRINT( std::cerr << "not current..." << std::endl; )
244        return expr;
245}
246
247void AddressRef::previsit( ast::Expr const * expr ) {
248        handleNonAddr( expr );
249        GuardValue( addCast ) = false;
250}
251
252// So we want to skip traversing to the head?
253ast::ApplicationExpr const * AddressRef::previsit(
254                ast::ApplicationExpr const * expr ) {
255        visit_children = false;
256        GuardValue( addCast );
257        handleNonAddr( expr );
258        auto mutExpr = ast::mutate( expr );
259        for ( ast::ptr<ast::Expr> & arg : mutExpr->args ) {
260                addCast = true;
261                arg = arg->accept( *visitor );
262        }
263        return mutExpr;
264}
265
266void AddressRef::previsit( ast::SingleInit const * ) {
267        // Each initialization context with address-of requires a cast.
268        GuardValue( addCast ) = true;
269}
270
271// idea: &&&E: get outer &, inner &
272// at inner &, record depth D of reference type of argument of &.
273// at auter &, add D derefs.
274void AddressRef::handleNonAddr( ast::Expr const * ) {
275        // non-address-of: reset status variables:
276        // * current expr is NOT the first address-of expr in an address-of chain.
277        // * next seen address-of expr IS the first in the chain.
278        GuardValue( current ) = false;
279        GuardValue( first ) = true;
280}
281
282ast::Expr const * ReferenceConversions::postvisit(
283                ast::CastExpr const * expr ) {
284        // TODO: Is it possible to convert directly between reference types with
285        // a different base. e.g.
286        //   int x;
287        //   (double&)x;
288        // At the moment, I (who?) am working off of the assumption that this is
289        // illegal, thus the cast becomes redundant after this pass, so trash the
290        // cast altogether. If that changes, care must be taken to insert the
291        // correct pointer casts in the right places.
292
293        // Note: reference depth difference is the determining factor in what
294        // code is run, rather than whether something is reference type or not,
295        // since conversion still needs to occur when both types are references
296        // that differ in depth.
297        ast::Type const * dstType = expr->result.get();
298        ast::Type const * srcType = expr->arg->result.get();
299        assertf( dstType, "Cast to no type in: %s", toCString( expr ) );
300        assertf( srcType, "Cast from no type in: %s", toCString( expr ) );
301        int dstDepth = dstType->referenceDepth();
302        int srcDepth = srcType->referenceDepth();
303        int diff = dstDepth - srcDepth;
304
305        if ( 0 < diff && !expr->arg->get_lvalue() ) {
306                // rvalue to reference conversion -- introduce temporary
307                // know that reference depth of cast argument is 0
308                //   (int &&&)3;
309                // becomes
310                //   int __ref_tmp_0 = 3;
311                //   int & __ref_tmp_1 = &__ref_tmp_0;
312                //   int && __ref_tmp_2 = &__ref_tmp_1;
313                //   &__ref_tmp_2;
314                // The last & comes from the remaining reference conversion code.
315                SemanticWarning( expr->arg->location,
316                        Warning::RvalueToReferenceConversion, toCString( expr->arg ) );
317
318                static UniqueName tmpNamer( "__ref_tmp_" );
319                ast::ObjectDecl * tmp = new ast::ObjectDecl( expr->arg->location,
320                        tmpNamer.newName(),
321                        ast::deepCopy( expr->arg->result ),
322                        new ast::SingleInit( expr->arg->location, expr->arg ) );
323                PRINT( std::cerr << "make tmp: " << tmp << std::endl; )
324                stmtsToAddBefore.push_back( new ast::DeclStmt( tmp->location, tmp ) );
325                for ( int i = 0 ; i < dstDepth - 1 ; ++i ) {
326                        ast::ObjectDecl * newTmp = new ast::ObjectDecl( tmp->location,
327                                tmpNamer.newName(),
328                                new ast::ReferenceType( ast::deepCopy( tmp->type ) ),
329                                new ast::SingleInit( tmp->location,
330                                        new ast::AddressExpr( tmp->location,
331                                                new ast::VariableExpr( tmp->location, tmp ) ) ) );
332                        PRINT( std::cerr << "make tmp: " << i << ": " << newTmp << std::endl; )
333                        stmtsToAddBefore.push_back(
334                                new ast::DeclStmt( newTmp->location, newTmp ) );
335                        tmp = newTmp;
336                }
337                // Update diff so that remaining code works out correctly.
338                expr = ast::mutate_field( expr, &ast::CastExpr::arg,
339                        new ast::VariableExpr( tmp->location, tmp ) );
340                PRINT( std::cerr << "update cast to: " << expr << std::endl; )
341                srcType = expr->arg->result;
342                srcDepth = srcType->referenceDepth();
343                diff = dstDepth - srcDepth;
344                assert( 1 == diff );
345        }
346
347        // Handle conversion between different depths.
348        PRINT(
349                if ( dstDepth || srcDepth ) {
350                        std::cerr << "dstType: " << dstType << " / srcType: " << srcType << '\n';
351                        std::cerr << "depth: " << dstDepth << " / " << srcDepth << std::endl;
352                }
353        )
354        // Conversion to type with more depth/more references.
355        // Add address-of for each level of difference.
356        if ( 0 < diff ) {
357                ast::Expr * ret = ast::mutate( expr->arg.get() );
358                for ( int i = 0 ; i < diff ; ++i ) {
359                        ret = new ast::AddressExpr( ret->location, ret );
360                }
361                if ( expr->arg->get_lvalue() &&
362                                !ResolvExpr::typesCompatible(
363                                        srcType,
[251ce80]364                                        strict_dynamic_cast<ast::ReferenceType const *>( dstType )->base ) ) {
[7fffb1b]365                        // Must keep cast if cast-to type is different from the actual type.
366                        return ast::mutate_field( expr, &ast::CastExpr::arg, ret );
367                }
368                ret->env = expr->env;
369                ret->result = expr->result;
370                return ret;
371        // Conversion to type with less depth/fewer references.
372        // Add dereferences for each level of difference.
373        } else if ( diff < 0 ) {
374                ast::Expr * ret = ast::mutate( expr->arg.get() );
375                for ( int i = 0 ; i < -diff ; ++i ) {
376                        ret = mkDeref( transUnit().global, ret );
377                }
378                // Must keep cast if types are different.
379                if ( !ResolvExpr::typesCompatibleIgnoreQualifiers(
380                                dstType->stripReferences(),
[251ce80]381                                srcType->stripReferences() ) ) {
[7fffb1b]382                        return ast::mutate_field( expr, &ast::CastExpr::arg, ret );
383                }
384                ret->env = expr->env;
385                ret->result = expr->result;
386                // The result must be an lvalue.
387                assert( ret->get_lvalue() );
388                return ret;
389        // Conversion with the same depth.
390        } else {
391                assert( 0 == diff );
392                // Remove useless generated casts.
[85855b0]393                if ( expr->isGenerated == ast::GeneratedFlag::GeneratedCast &&
[7fffb1b]394                                ResolvExpr::typesCompatible(
395                                        expr->result,
[251ce80]396                                        expr->arg->result ) ) {
[7fffb1b]397                        PRINT(
398                                std::cerr << "types are compatible, removing cast: " << expr << '\n';
399                                std::cerr << "-- " << expr->result << '\n';
400                                std::cerr << "-- " << expr->arg->result << std::endl;
401                        )
[85855b0]402                        auto argAsEnum = expr->arg.as<ast::EnumInstType>();
403                        auto resultAsEnum = expr->result.as<ast::EnumInstType>();
404                        if (argAsEnum && resultAsEnum) {
405                                if (argAsEnum->base->name != resultAsEnum->base->name) {
406                                        return expr;
407                                }
408                        }
[7fffb1b]409                        return ast::mutate_field( expr->arg.get(),
410                                        &ast::Expr::env, expr->env.get() );
411                }
412                return expr;
413        }
414}
415
416ast::Expr const * ReferenceConversions::postvisit(
417                ast::AddressExpr const * expr ) {
418        // Inner expression may have been lvalue to reference conversion, which
419        // becomes an address expression. In this case, remove the outer address
420        // expression and return the argument.
421        // TODO: It's possible that this might catch too much and require a more
422        // sophisticated check. TODO What check are we talking about here?
423        return expr;
424}
425
426ast::Expr const * FixIntrinsicArgs::postvisit(
427                ast::ApplicationExpr const * expr ) {
428        // Intrinsic functions don't really take reference-typed parameters,
429        // so they require an implicit dereference on their arguments.
430        auto function = ast::getFunction( expr );
431        if ( function == nullptr ) {
432                return expr;
433        }
434
435        ast::FunctionType const * ftype = GenPoly::getFunctionType( function->get_type() );
436        assertf( ftype, "Function declaration does not have function type." );
437        // Can be of different lengths only when function is variadic.
438        assertf( ftype->params.size() == expr->args.size() || ftype->isVarArgs,
439                "ApplicationExpr args do not match formal parameter type." );
440        assertf( ftype->params.size() <= expr->args.size(),
441                "Cannot have more parameters than arguments." );
442
443        unsigned int i = 0;
444        unsigned int const end = ftype->params.size();
445
446        // This is used to make sure we get a zip on shortests.
447        if ( end == i ) return expr;
448
449        // This mutate could be redundent, but it is simpler this way.
450        auto mutExpr = ast::mutate( expr );
451
452        for ( auto pair : unsafe_group_iterate( mutExpr->args, ftype->params ) ) {
453                ast::ptr<ast::Expr> & arg = std::get<0>( pair );
454                ast::ptr<ast::Type> const & formal = std::get<1>( pair );
455                PRINT(
456                        std::cerr << "pair<0>: " << arg.get() << std::endl;
457                        std::cerr << " -- " << arg->result << std::endl;
458                        std::cerr << "pair<1>: " << formal << std::endl;
459                )
460                //if ( dynamic_cast<ast::ReferenceType const *>( formal.get() ) ) {
461                if ( formal.as<ast::ReferenceType>() ) {
462                        PRINT( std::cerr << "===formal is reference" << std::endl; )
463                        // TODO: It's likely that the second condition should be
464                        // `... && ! isIntrinsicReference( arg )`, but this requires
465                        // investigation.
466
467                        if ( ast::Linkage::Intrinsic != function->linkage
468                                        && isIntrinsicReference( arg ) ) {
469                                // Needed for definition of prelude functions, etc.
470                                // If argument is dereference or array subscript, the result
471                                // isn't REALLY a reference, but non-intrinsic functions
472                                // expect a reference: take address
473
474                                // TODO: OK, so this should be cut?!
475                                // NODE: Previously, this condition fixed
476                                //   void f(int *&);
477                                //   int & x = ...;
478                                //   f(&x);
479                                // But now this is taken care of by a reference cast added by
480                                // AddressRef. Need to find a new example or remove this
481                                // branch.
482                                PRINT(
483                                        std::cerr << "===is intrinsic arg in non-intrinsic call - adding address" << std::endl;
484                                )
485                                arg = new ast::AddressExpr( arg->location, arg );
486                        } else if ( ast::Linkage::Intrinsic == function->linkage
487                                        && arg->result->referenceDepth() != 0 ) {
488                                // Argument is a 'real' reference, but function expects a C
489                                // lvalue: Add a dereference to the reference-typed argument.
490                                PRINT(
491                                        std::cerr << "===is non-intrinsic arg in intrinsic call - adding deref to arg" << std::endl;
492                                )
493                                ast::Type const * base = ast::getPointerBase( arg->result );
494                                assertf( base, "parameter is reference, arg must be pointer or reference: %s", toString( arg->result ).c_str() );
495                                ast::PointerType * ptr = new ast::PointerType( ast::deepCopy( base ) );
496                                arg = ast::mutate_field( arg.get(),
497                                                &ast::ApplicationExpr::result, ptr );
498                                arg = mkDeref( transUnit().global, arg );
499                        }
500                }
501                ++i;
502                if ( end == i ) break;
503        }
504        return mutExpr;
505}
506
507ast::Expr const * CollapseAddressDeref::postvisit(
508                ast::AddressExpr const * expr ) {
509        ast::Expr const * arg = expr->arg;
510        if ( isIntrinsicReference( arg ) ) {
511                std::string fname = ast::getFunctionName( arg );
512                if ( fname == "*?" ) {
513                        ast::Expr const * arg0 = ast::getCallArg( arg, 0 );
514                        ast::Expr * ret = ast::mutate( arg0 );
515                        ret->env = expr->env;
516                        return ret;
517                }
518        } else if ( auto cast = dynamic_cast<ast::CastExpr const *>( arg ) ) {
519                // Need to move cast to pointer type out a level since address of
520                // pointer is not valid C code (can be introduced in prior passes,
521                // e.g., InstantiateGeneric)
522                if ( ast::getPointerBase( cast->result ) ) {
523                        auto mutExpr = ast::mutate( expr );
524                        auto mutCast = strict_dynamic_cast<ast::CastExpr *>(
525                                        ast::mutate( mutExpr->arg.release() ) );
526                        mutExpr->arg = mutCast->arg;
527                        mutCast->arg = mutExpr;
528                        mutCast->result = new ast::PointerType( mutCast->result );
529                        return mutCast;
530                }
531        }
532        return expr;
533}
534
535ast::Expr const * CollapseAddressDeref::postvisit(
536                ast::ApplicationExpr const * expr ) {
537        if ( isIntrinsicReference( expr ) ) {
538                std::string fname = ast::getFunctionName( expr );
539                if ( fname == "*?" ) {
540                        assert( 1 == expr->args.size() );
541                        ast::Expr const * arg = ast::getCallArg( expr, 0 );
542                        // xxx - this isn't right, because it can remove casts that
543                        // should be there...
544                        //      while ( auto cast = dynamic_cast< ast::CastExpr const * >( arg ) ) {
545                        //              arg = cast->arg;
546                        //      }
547                        if ( auto addr = dynamic_cast<ast::AddressExpr const *>( arg ) ) {
548                                return ast::mutate_field( addr->arg.get(),
549                                                &ast::Expr::env, expr->env.get() );
550                        }
551                }
552        }
553        return expr;
554}
555
556ast::Expr const * GeneralizedLvalue::postvisit(
557                ast::AddressExpr const * expr ) {
558        return applyTransformation( expr, &ast::AddressExpr::arg,
559                []( ast::Expr const * arg ) {
560                        return new ast::AddressExpr( arg->location, arg );
561                }
562        );
563}
564
565ast::Expr const * GeneralizedLvalue::postvisit(
566                ast::MemberExpr const * expr ) {
567        return applyTransformation( expr, &ast::MemberExpr::aggregate,
568                [expr]( ast::Expr const * aggr ) {
569                        return new ast::MemberExpr( aggr->location, expr->member, aggr );
570                }
571        );
572}
573
574template<typename Node, typename Func>
575ast::Expr const * GeneralizedLvalue::applyTransformation(
576                Node const * expr, ast::ptr<ast::Expr> Node::*field, Func mkExpr ) {
577        ast::ptr<ast::Expr> const & arg = expr->*field;
578        if ( auto commaArg = arg.as<ast::CommaExpr>() ) {
579                ast::Expr const * arg1 = ast::deepCopy( commaArg->arg1 );
580                ast::Expr const * arg2 = ast::deepCopy( commaArg->arg2 );
581                ast::Expr const * ret = new ast::CommaExpr(
582                        commaArg->location, arg1, mkExpr( arg2 )->accept( *visitor ) );
583                return ret;
584        } else if ( auto condArg = arg.as<ast::ConditionalExpr>() ) {
585                ast::Expr const * arg1 = ast::deepCopy( condArg->arg1 );
586                ast::Expr const * arg2 = ast::deepCopy( condArg->arg2 );
587                ast::Expr const * arg3 = ast::deepCopy( condArg->arg3 );
588                ast::ConditionalExpr * ret = new ast::ConditionalExpr(
589                        condArg->location, arg1, mkExpr( arg2 )->accept( *visitor ),
590                        mkExpr( arg3 )->accept( *visitor ) );
591
592                // Conditional expr type may not be either of the arguments,
593                // so unify to get the result.
594                // TODO: Maybe I could create a wrapper for this.
595                ast::ptr<ast::Type> common = nullptr;
596                ast::TypeEnvironment newEnv;
597                ast::AssertionSet needAssertions, haveAssertions;
598                ast::OpenVarSet openVars;
599                ResolvExpr::unify( ret->arg2->result, ret->arg3->result, newEnv,
[251ce80]600                        needAssertions, haveAssertions, openVars, common );
[7fffb1b]601                ret->result = common ? common : ast::deepCopy( ret->arg2->result );
602                return ret;
603        }
604        return expr;
605}
606
[97f8f0f]607ast::SizeofExpr const * ReferenceTypeElimination::previsit(
608                ast::SizeofExpr const * expr ) {
609        return ast::mutate_field( expr, &ast::SizeofExpr::type,
610                expr->type->stripReferences() );
611}
612
613ast::AlignofExpr const * ReferenceTypeElimination::previsit(
614                ast::AlignofExpr const * expr ) {
615        return ast::mutate_field( expr, &ast::AlignofExpr::type,
616                expr->type->stripReferences() );
617}
618
[7fffb1b]619ast::Type const * ReferenceTypeElimination::postvisit(
620                ast::ReferenceType const * type ) {
621        return new ast::PointerType( type->base, type->qualifiers );
622}
623
624} // namespace
625
626// Stored elsewhere (Lvalue2, initially false):
627extern bool referencesEliminated;
628
629void convertLvalue( ast::TranslationUnit & translationUnit ) {
630        ast::Pass<FixIntrinsicResults>::run( translationUnit );
631        ast::Pass<AddressRef>::run( translationUnit );
632        ast::Pass<ReferenceConversions>::run( translationUnit );
633        ast::Pass<FixIntrinsicArgs>::run( translationUnit );
634        ast::Pass<CollapseAddressDeref>::run( translationUnit );
635        ast::Pass<GeneralizedLvalue>::run( translationUnit );
636        // Last because other passes need reference types to work.
637        ast::Pass<ReferenceTypeElimination>::run( translationUnit );
638        // From this point forward, nothing should create reference types.
639        referencesEliminated = true;
640}
641
642ast::Expr const * generalizedLvalue( ast::Expr const * expr ) {
643        ast::Pass<GeneralizedLvalue> visitor;
644        return expr->accept( visitor );
645}
646
647} // namespace GenPoly
648
649// Local Variables: //
650// tab-width: 4 //
651// mode: c++ //
652// compile-command: "make install" //
653// End: //
Note: See TracBrowser for help on using the repository browser.