source: src/GenPoly/Lvalue.cpp@ 174a11a

Last change on this file since 174a11a was b6f2e7ab, checked in by Andrew Beach <ajbeach@…>, 13 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
Line 
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//
7// Lvalue.cpp -- Clean up lvalues and remove references.
8//
9// Author : Andrew Beach
10// Created On : Thu Sep 15 14:08:00 2022
11// Last Modified By : Andrew Beach
12// Last Modified On : Mon Aug 12 18:07:00 2024
13// Update Count : 1
14//
15
16#include "Lvalue.hpp"
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"
26#include "Common/SemanticError.hpp" // for SemanticWarning
27#include "Common/ToString.hpp" // for toCString
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
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 {
121 ast::SizeofExpr const * previsit( ast::SizeofExpr const * expr );
122 ast::AlignofExpr const * previsit( ast::AlignofExpr const * expr );
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 ) {
165
166 if ( skip == SkipInProgress || !isIntrinsicReference( expr ) ) {
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,
364 strict_dynamic_cast<ast::ReferenceType const *>( dstType )->base ) ) {
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(),
381 srcType->stripReferences() ) ) {
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.
393 if ( expr->isGenerated == ast::GeneratedFlag::GeneratedCast &&
394 ResolvExpr::typesCompatible(
395 expr->result,
396 expr->arg->result ) ) {
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 )
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 }
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,
600 needAssertions, haveAssertions, openVars, common );
601 ret->result = common ? common : ast::deepCopy( ret->arg2->result );
602 return ret;
603 }
604 return expr;
605}
606
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
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.