source: src/GenPoly/Box.cpp @ dd900b5

Last change on this file since dd900b5 was dd900b5, checked in by Andrew Beach <ajbeach@…>, 19 months ago

Implicit and layout parameters are now marked as const. This is primarily a safety feature to catch bad writes.

  • Property mode set to 100644
File size: 81.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// Box.cpp -- Implement polymorphic function calls and types.
8//
9// Author           : Andrew Beach
10// Created On       : Thr Oct  6 13:39:00 2022
11// Last Modified By : Andrew Beach
12// Last Modified On : Mon Oct  2 17:00:00 2023
13// Update Count     : 0
14//
15
16#include "Box.h"
17
18#include "AST/Decl.hpp"                // for Decl, FunctionDecl, ...
19#include "AST/Expr.hpp"                // for AlignofExpr, ConstantExpr, ...
20#include "AST/Init.hpp"                // for Init, SingleInit
21#include "AST/Inspect.hpp"             // for getFunctionName
22#include "AST/Pass.hpp"                // for Pass, WithDeclsToAdd, ...
23#include "AST/Stmt.hpp"                // for CompoundStmt, ExprStmt, ...
24#include "AST/Vector.hpp"              // for vector
25#include "AST/GenericSubstitution.hpp" // for genericSubstitution
26#include "CodeGen/OperatorTable.h"     // for isAssignment
27#include "Common/ScopedMap.h"          // for ScopedMap
28#include "Common/UniqueName.h"         // for UniqueName
29#include "Common/utility.h"            // for toCString, group_iterate
30#include "GenPoly/FindFunction.h"      // for findFunction
31#include "GenPoly/GenPoly.h"           // for getFunctionType, ...
32#include "GenPoly/Lvalue.h"            // for generalizedLvalue
33#include "GenPoly/ScopedSet.h"         // for ScopedSet
34#include "GenPoly/ScrubTypeVars.hpp"   // for scrubTypeVars, scrubAllTypeVars
35#include "ResolvExpr/Unify.h"          // for typesCompatible
36#include "SymTab/Mangler.h"            // for mangle, mangleType
37
38namespace GenPoly {
39
40namespace {
41
42/// The layout type is used to represent sizes, alignments and offsets.
43ast::BasicType * makeLayoutType() {
44        return new ast::BasicType( ast::BasicType::LongUnsignedInt );
45}
46
47/// Fixed version of layout type (just adding a 'C' in C++ style).
48ast::BasicType * makeLayoutCType() {
49        return new ast::BasicType( ast::BasicType::LongUnsignedInt,
50                ast::CV::Qualifiers( ast::CV::Const ) );
51}
52
53// --------------------------------------------------------------------------
54/// Adds layout-generation functions to polymorphic types.
55struct LayoutFunctionBuilder final :
56                public ast::WithDeclsToAdd<>,
57                public ast::WithShortCircuiting,
58                public ast::WithVisitorRef<LayoutFunctionBuilder> {
59        void previsit( ast::StructDecl const * decl );
60        void previsit( ast::UnionDecl const * decl );
61};
62
63/// Get all sized type declarations; those that affect a layout function.
64ast::vector<ast::TypeDecl> takeSizedParams(
65                ast::vector<ast::TypeDecl> const & decls ) {
66        ast::vector<ast::TypeDecl> sizedParams;
67        for ( ast::ptr<ast::TypeDecl> const & decl : decls ) {
68                if ( decl->isComplete() ) {
69                        sizedParams.emplace_back( decl );
70                }
71        }
72        return sizedParams;
73}
74
75/// Adds parameters for otype size and alignment to a function type.
76void addSTypeParams(
77                ast::vector<ast::DeclWithType> & params,
78                ast::vector<ast::TypeDecl> const & sizedParams ) {
79        for ( ast::ptr<ast::TypeDecl> const & sizedParam : sizedParams ) {
80                ast::TypeInstType inst( sizedParam );
81                std::string paramName = Mangle::mangleType( &inst );
82                params.emplace_back( new ast::ObjectDecl(
83                        sizedParam->location,
84                        sizeofName( paramName ),
85                        makeLayoutCType()
86                ) );
87                params.emplace_back( new ast::ObjectDecl(
88                        sizedParam->location,
89                        alignofName( paramName ),
90                        makeLayoutCType()
91                ) );
92        }
93}
94
95ast::Type * makeLayoutOutType() {
96        return new ast::PointerType( makeLayoutType() );
97}
98
99struct LayoutData {
100        ast::FunctionDecl * function;
101        ast::ObjectDecl * sizeofParam;
102        ast::ObjectDecl * alignofParam;
103        ast::ObjectDecl * offsetofParam;
104};
105
106LayoutData buildLayoutFunction(
107                CodeLocation const & location, ast::AggregateDecl const * aggr,
108                ast::vector<ast::TypeDecl> const & sizedParams,
109                bool isInFunction, bool isStruct ) {
110        ast::ObjectDecl * sizeParam = new ast::ObjectDecl(
111                location,
112                sizeofName( aggr->name ),
113                makeLayoutOutType()
114        );
115        ast::ObjectDecl * alignParam = new ast::ObjectDecl(
116                location,
117                alignofName( aggr->name ),
118                makeLayoutOutType()
119        );
120        ast::ObjectDecl * offsetParam = nullptr;
121        ast::vector<ast::DeclWithType> params = { sizeParam, alignParam };
122        if ( isStruct ) {
123                offsetParam = new ast::ObjectDecl(
124                        location,
125                        offsetofName( aggr->name ),
126                        makeLayoutOutType()
127                );
128                params.push_back( offsetParam );
129        }
130        addSTypeParams( params, sizedParams );
131
132        // Routines at global scope marked "static" to prevent multiple
133        // definitions is separate translation units because each unit generates
134        // copies of the default routines for each aggregate.
135        ast::FunctionDecl * layoutDecl = new ast::FunctionDecl(
136                location,
137                layoutofName( aggr ),
138                {}, // forall
139                {}, // assertions
140                std::move( params ),
141                {}, // returns
142                new ast::CompoundStmt( location ),
143                isInFunction ? ast::Storage::Classes() : ast::Storage::Static,
144                ast::Linkage::AutoGen,
145                {}, // attrs
146                ast::Function::Inline,
147                ast::FixedArgs
148        );
149        layoutDecl->fixUniqueId();
150        return LayoutData{ layoutDecl, sizeParam, alignParam, offsetParam };
151}
152
153/// Makes a binary operation.
154ast::Expr * makeOp( CodeLocation const & location, std::string const & name,
155                ast::Expr const * lhs, ast::Expr const * rhs ) {
156        return new ast::UntypedExpr( location,
157                new ast::NameExpr( location, name ), { lhs, rhs } );
158}
159
160/// Make a binary operation and wrap it in a statement.
161ast::Stmt * makeOpStmt( CodeLocation const & location, std::string const & name,
162                ast::Expr const * lhs, ast::Expr const * rhs ) {
163        return new ast::ExprStmt( location, makeOp( location, name, lhs, rhs ) );
164}
165
166/// Returns the dereference of a local pointer variable.
167ast::Expr * derefVar(
168                CodeLocation const & location, ast::ObjectDecl const * var ) {
169        return ast::UntypedExpr::createDeref( location,
170                new ast::VariableExpr( location, var ) );
171}
172
173/// Makes an if-statement with a single-expression then and no else.
174ast::Stmt * makeCond( CodeLocation const & location,
175                ast::Expr const * cond, ast::Expr const * thenPart ) {
176        return new ast::IfStmt( location,
177                cond, new ast::ExprStmt( location, thenPart ), nullptr );
178}
179
180/// Makes a statement that aligns lhs to rhs (rhs should be an integer
181/// power of two).
182ast::Stmt * makeAlignTo( CodeLocation const & location,
183                ast::Expr const * lhs, ast::Expr const * rhs ) {
184        // Check that the lhs is zeroed out to the level of rhs.
185        ast::Expr * ifCond = makeOp( location, "?&?", lhs,
186                makeOp( location, "?-?", rhs,
187                                ast::ConstantExpr::from_ulong( location, 1 ) ) );
188        // If not aligned, increment to alignment.
189        ast::Expr * ifExpr = makeOp( location, "?+=?", ast::deepCopy( lhs ),
190                makeOp( location, "?-?", ast::deepCopy( rhs ),
191                                ast::deepCopy( ifCond ) ) );
192        return makeCond( location, ifCond, ifExpr );
193}
194
195/// Makes a statement that assigns rhs to lhs if lhs < rhs.
196ast::Stmt * makeAssignMax( CodeLocation const & location,
197                ast::Expr const * lhs, ast::Expr const * rhs ) {
198        return makeCond( location,
199                makeOp( location, "?<?", ast::deepCopy( lhs ), ast::deepCopy( rhs ) ),
200                makeOp( location, "?=?", lhs, rhs ) );
201}
202
203void LayoutFunctionBuilder::previsit( ast::StructDecl const * decl ) {
204        // Do not generate layout function for empty tag structures.
205        visit_children = false;
206        if ( decl->members.empty() ) return;
207
208        // Get parameters that can change layout, exiting early if none.
209        ast::vector<ast::TypeDecl> sizedParams =
210                takeSizedParams( decl->params );
211        if ( sizedParams.empty() ) return;
212
213        CodeLocation const & location = decl->location;
214
215        // Build layout function signature.
216        LayoutData layout = buildLayoutFunction(
217                location, decl, sizedParams, isInFunction(), true );
218        ast::FunctionDecl * layoutDecl = layout.function;
219        // Also return these or extract them from the parameter list?
220        ast::ObjectDecl const * sizeofParam = layout.sizeofParam;
221        ast::ObjectDecl const * alignofParam = layout.alignofParam;
222        ast::ObjectDecl const * offsetofParam = layout.offsetofParam;
223        assert( nullptr != layout.offsetofParam );
224
225        // Calculate structure layout in function body.
226        // Initialize size and alignment to 0 and 1
227        // (Will have at least one member to update size).
228        auto & kids = layoutDecl->stmts.get_and_mutate()->kids;
229        kids.emplace_back( makeOpStmt( location, "?=?",
230                derefVar( location, sizeofParam ),
231                ast::ConstantExpr::from_ulong( location, 0 )
232        ) );
233        kids.emplace_back( makeOpStmt( location, "?=?",
234                derefVar( location, alignofParam ),
235                ast::ConstantExpr::from_ulong( location, 1 )
236        ) );
237        // TODO: Polymorphic types will be out of the struct declaration scope.
238        // Should be removed by PolyGenericCalculator.
239        for ( auto const & member : enumerate( decl->members ) ) {
240                auto dwt = member.val.strict_as<ast::DeclWithType>();
241                ast::Type const * memberType = dwt->get_type();
242
243                if ( 0 < member.idx ) {
244                        // Make sure all later members have padding to align them.
245                        kids.emplace_back( makeAlignTo( location,
246                                derefVar( location, sizeofParam ),
247                                new ast::AlignofExpr( location, ast::deepCopy( memberType ) )
248                        ) );
249                }
250
251                // Place current size in the current offset index.
252                kids.emplace_back( makeOpStmt( location, "?=?",
253                        makeOp( location, "?[?]",
254                                new ast::VariableExpr( location, offsetofParam ),
255                                ast::ConstantExpr::from_ulong( location, member.idx ) ),
256                        derefVar( location, sizeofParam ) ) );
257
258                // Add member size to current size.
259                kids.emplace_back( makeOpStmt( location, "?+=?",
260                        derefVar( location, sizeofParam ),
261                        new ast::SizeofExpr( location, ast::deepCopy( memberType ) ) ) );
262
263                // Take max of member alignment and global alignment.
264                // (As align is always 2^n, this will always be a multiple of both.)
265                kids.emplace_back( makeAssignMax( location,
266                        derefVar( location, alignofParam ),
267                        new ast::AlignofExpr( location, ast::deepCopy( memberType ) ) ) );
268        }
269        // Make sure the type is end-padded to a multiple of its alignment.
270        kids.emplace_back( makeAlignTo( location,
271                derefVar( location, sizeofParam ),
272                derefVar( location, alignofParam ) ) );
273
274        declsToAddAfter.emplace_back( layoutDecl );
275}
276
277void LayoutFunctionBuilder::previsit( ast::UnionDecl const * decl ) {
278        visit_children = false;
279        // Do not generate layout function for empty tag unions.
280        if ( decl->members.empty() ) return;
281
282        // Get parameters that can change layout, exiting early if none.
283        ast::vector<ast::TypeDecl> sizedParams =
284                takeSizedParams( decl->params );
285        if ( sizedParams.empty() ) return;
286
287        CodeLocation const & location = decl->location;
288
289        // Build layout function signature.
290        LayoutData layout = buildLayoutFunction(
291                location, decl, sizedParams, isInFunction(), false );
292        ast::FunctionDecl * layoutDecl = layout.function;
293        // Also return these or extract them from the parameter list?
294        ast::ObjectDecl const * sizeofParam = layout.sizeofParam;
295        ast::ObjectDecl const * alignofParam = layout.alignofParam;
296        assert( nullptr == layout.offsetofParam );
297
298        // Calculate union layout in function body.
299        // Both are simply the maximum for union (actually align is always the
300        // LCM, but with powers of two that is also the maximum).
301        auto & kids = layoutDecl->stmts.get_and_mutate()->kids;
302        kids.emplace_back( makeOpStmt( location,
303                "?=?", derefVar( location, sizeofParam ),
304                ast::ConstantExpr::from_ulong( location, 1 )
305        ) );
306        kids.emplace_back( makeOpStmt( location,
307                "?=?", derefVar( location, alignofParam ),
308                ast::ConstantExpr::from_ulong( location, 1 )
309        ) );
310        // TODO: Polymorphic types will be out of the union declaration scope.
311        for ( auto const & member : decl->members ) {
312                auto dwt = member.strict_as<ast::DeclWithType>();
313                ast::Type const * memberType = dwt->get_type();
314
315                // Take max member size and global size.
316                kids.emplace_back( makeAssignMax( location,
317                        derefVar( location, sizeofParam ),
318                        new ast::SizeofExpr( location, ast::deepCopy( memberType ) )
319                ) );
320
321                // Take max of member alignment and global alignment.
322                kids.emplace_back( makeAssignMax( location,
323                        derefVar( location, alignofParam ),
324                        new ast::AlignofExpr( location, ast::deepCopy( memberType ) )
325                ) );
326        }
327        kids.emplace_back( makeAlignTo( location,
328                derefVar( location, sizeofParam ),
329                derefVar( location, alignofParam ) ) );
330
331        declsToAddAfter.emplace_back( layoutDecl );
332}
333
334// --------------------------------------------------------------------------
335/// Application expression transformer.
336/// * Replaces polymorphic return types with out-parameters.
337/// * Replaces call to polymorphic functions with adapter calls which handles
338///   dynamic arguments and return values.
339/// * Adds appropriate type variables to the function calls.
340struct CallAdapter final :
341                public ast::WithConstTypeSubstitution,
342                public ast::WithGuards,
343                public ast::WithShortCircuiting,
344                public ast::WithStmtsToAdd<>,
345                public ast::WithVisitorRef<CallAdapter> {
346        CallAdapter();
347
348        void previsit( ast::Decl const * decl );
349        ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl );
350        void previsit( ast::TypeDecl const * decl );
351        void previsit( ast::CommaExpr const * expr );
352        ast::Expr const * postvisit( ast::ApplicationExpr const * expr );
353        ast::Expr const * postvisit( ast::UntypedExpr const * expr );
354        void previsit( ast::AddressExpr const * expr );
355        ast::Expr const * postvisit( ast::AddressExpr const * expr );
356        ast::ReturnStmt const * previsit( ast::ReturnStmt const * stmt );
357
358        void beginScope();
359        void endScope();
360private:
361        // Many helpers here use a mutable ApplicationExpr as an in/out parameter
362        // instead of using the return value, to save on mutates and free up the
363        // return value.
364
365        /// Passes extra layout arguments for sized polymorphic type parameters.
366        ast::vector<ast::Expr>::iterator passTypeVars(
367                ast::ApplicationExpr * expr,
368                ast::FunctionType const * funcType );
369        /// Wraps a function application with a new temporary for the
370        /// out-parameter return value.
371        ast::Expr const * addRetParam(
372                ast::ApplicationExpr * expr, ast::Type const * retType );
373        /// Wraps a function application returning a polymorphic type with a new
374        /// temporary for the out-parameter return value.
375        ast::Expr const * addDynRetParam(
376                ast::ApplicationExpr * expr, ast::Type const * polyType );
377        /// Modify a call so it passes the function through the correct adapter.
378        ast::Expr const * applyAdapter(
379                ast::ApplicationExpr * expr,
380                ast::FunctionType const * function );
381        /// Convert a single argument into its boxed form to pass the parameter.
382        void boxParam( ast::ptr<ast::Expr> & arg,
383                ast::Type const * formal, TypeVarMap const & exprTyVars );
384        /// Box every argument from arg forward, matching the functionType
385        /// parameter list. arg should point into expr's argument list.
386        void boxParams(
387                ast::ApplicationExpr const * expr,
388                ast::vector<ast::Expr>::iterator arg,
389                ast::FunctionType const * function,
390                const TypeVarMap & typeVars );
391        /// Adds the inferred parameters derived from the assertions of the
392        /// expression to the call.
393        void addInferredParams(
394                ast::ApplicationExpr * expr,
395                ast::vector<ast::Expr>::iterator arg,
396                ast::FunctionType const * functionType,
397                const TypeVarMap & typeVars );
398        /// Stores assignment operators from assertion list in
399        /// local map of assignment operations.
400        void passAdapters(
401                ast::ApplicationExpr * expr,
402                ast::FunctionType const * type,
403                const TypeVarMap & typeVars );
404        /// Create an adapter function based on the type of the adaptee and the
405        /// real type with the type substitutions applied.
406        ast::FunctionDecl * makeAdapter(
407                ast::FunctionType const * adaptee,
408                ast::FunctionType const * realType,
409                std::string const & mangleName,
410                TypeVarMap const & typeVars,
411                CodeLocation const & location ) const;
412        /// Replaces intrinsic operator functions with their arithmetic desugaring.
413        ast::Expr const * handleIntrinsics( ast::ApplicationExpr const * );
414        /// Inserts a new temporary variable into the current scope with an
415        /// auto-generated name.
416        ast::ObjectDecl * makeTemporary(
417                CodeLocation const & location, ast::Type const * type );
418
419        TypeVarMap scopeTypeVars;
420        ScopedMap< std::string, ast::DeclWithType const * > adapters;
421        std::map< ast::ApplicationExpr const *, ast::Expr const * > retVals;
422        ast::DeclWithType const * retval;
423        UniqueName tmpNamer;
424};
425
426/// Replaces a polymorphic type with its concrete equivalant under the
427/// current environment (returns itself if concrete).
428/// If `doClone` is set to false, will not clone interior types
429ast::Type const * replaceWithConcrete(
430                ast::Type const * type,
431                ast::TypeSubstitution const & typeSubs,
432                bool doCopy = true );
433
434/// Replaces all the type parameters of a generic type with their
435/// concrete equivalents under the current environment.
436void replaceParametersWithConcrete(
437                ast::vector<ast::Expr> & params,
438                ast::TypeSubstitution const & typeSubs ) {
439        for ( ast::ptr<ast::Expr> & paramExpr : params ) {
440                ast::TypeExpr const * param = paramExpr.as<ast::TypeExpr>();
441                assertf( param, "Aggregate parameters should be type expressions." );
442                paramExpr = ast::mutate_field( param, &ast::TypeExpr::type,
443                        replaceWithConcrete( param->type.get(), typeSubs, false ) );
444        }
445}
446
447ast::Type const * replaceWithConcrete(
448                ast::Type const * type,
449                ast::TypeSubstitution const & typeSubs,
450                bool doCopy ) {
451        if ( auto instType = dynamic_cast<ast::TypeInstType const *>( type ) ) {
452                ast::Type const * concrete = typeSubs.lookup( instType );
453                return ( nullptr != concrete ) ? concrete : instType;
454        } else if ( auto structType =
455                        dynamic_cast<ast::StructInstType const *>( type ) ) {
456                ast::StructInstType * newType =
457                        doCopy ? ast::deepCopy( structType ) : ast::mutate( structType );
458                replaceParametersWithConcrete( newType->params, typeSubs );
459                return newType;
460        } else if ( auto unionType =
461                        dynamic_cast<ast::UnionInstType const *>( type ) ) {
462                ast::UnionInstType * newType =
463                        doCopy ? ast::deepCopy( unionType ) : ast::mutate( unionType );
464                replaceParametersWithConcrete( newType->params, typeSubs );
465                return newType;
466        } else {
467                return type;
468        }
469}
470
471std::string makePolyMonoSuffix(
472                ast::FunctionType const * function,
473                TypeVarMap const & typeVars ) {
474        // If the return type or a parameter type involved polymorphic types,
475        // then the adapter will need to take those polymorphic types as pointers.
476        // Therefore, there can be two different functions with the same mangled
477        // name, so we need to further mangle the names.
478        std::stringstream name;
479        for ( auto ret : function->returns ) {
480                name << ( isPolyType( ret, typeVars ) ? 'P' : 'M' );
481        }
482        name << '_';
483        for ( auto arg : function->params ) {
484                name << ( isPolyType( arg, typeVars ) ? 'P' : 'M' );
485        }
486        return name.str();
487}
488
489std::string mangleAdapterName(
490                ast::FunctionType const * function,
491                TypeVarMap const & typeVars ) {
492        return Mangle::mangle( function, {} )
493                + makePolyMonoSuffix( function, typeVars );
494}
495
496std::string makeAdapterName( std::string const & mangleName ) {
497        return "_adapter" + mangleName;
498}
499
500void makeRetParam( ast::FunctionType * type ) {
501        ast::ptr<ast::Type> & retParam = type->returns.front();
502
503        // Make a new parameter that is a pointer to the type of the old return value.
504        retParam = new ast::PointerType( retParam.get() );
505        type->params.emplace( type->params.begin(), retParam );
506
507        // We don't need the return value any more.
508        type->returns.clear();
509}
510
511ast::FunctionType * makeAdapterType(
512                ast::FunctionType const * adaptee,
513                TypeVarMap const & typeVars ) {
514        ast::FunctionType * adapter = ast::deepCopy( adaptee );
515        if ( isDynRet( adapter, typeVars ) ) {
516                makeRetParam( adapter );
517        }
518        adapter->params.emplace( adapter->params.begin(),
519                new ast::PointerType( new ast::FunctionType( ast::VariableArgs ) )
520        );
521        return adapter;
522}
523
524CallAdapter::CallAdapter() : tmpNamer( "_temp" ) {}
525
526void CallAdapter::previsit( ast::Decl const * ) {
527        // Prevent type declaration information from leaking out.
528        GuardScope( scopeTypeVars );
529}
530
531ast::FunctionDecl const * CallAdapter::previsit( ast::FunctionDecl const * decl ) {
532        // Prevent type declaration information from leaking out.
533        GuardScope( scopeTypeVars );
534
535        if ( nullptr == decl->stmts ) {
536                return decl;
537        }
538
539        GuardValue( retval );
540
541        // Process polymorphic return value.
542        retval = nullptr;
543        ast::FunctionType const * type = decl->type;
544        if ( isDynRet( type ) && decl->linkage != ast::Linkage::C ) {
545                retval = decl->returns.front();
546
547                // Give names to unnamed return values.
548                if ( "" == retval->name ) {
549                        auto mutRet = ast::mutate( retval );
550                        mutRet->name = "_retparam";
551                        mutRet->linkage = ast::Linkage::C;
552                        retval = mutRet;
553                        decl = ast::mutate_field_index( decl,
554                                &ast::FunctionDecl::returns, 0, mutRet );
555                }
556        }
557
558        // The formal_usage/expr_id values may be off if we get them from the
559        // type, trying the declaration instead.
560        makeTypeVarMap( type, scopeTypeVars );
561
562        // Get all needed adapters from the call. We will forward them.
563        ast::vector<ast::FunctionType> functions;
564        for ( ast::ptr<ast::VariableExpr> const & assertion : type->assertions ) {
565                auto atype = assertion->result.get();
566                findFunction( atype, functions, scopeTypeVars, needsAdapter );
567        }
568
569        for ( ast::ptr<ast::Type> const & arg : type->params ) {
570                findFunction( arg, functions, scopeTypeVars, needsAdapter );
571        }
572
573        for ( auto funcType : functions ) {
574                std::string mangleName = mangleAdapterName( funcType, scopeTypeVars );
575                if ( adapters.contains( mangleName ) ) continue;
576                std::string adapterName = makeAdapterName( mangleName );
577                // TODO: The forwarding here is problematic because these
578                // declarations are not rooted anywhere in the translation unit.
579                adapters.insert(
580                        mangleName,
581                        new ast::ObjectDecl(
582                                decl->location,
583                                adapterName,
584                                new ast::PointerType(
585                                        makeAdapterType( funcType, scopeTypeVars ) ),
586                                nullptr, // init
587                                ast::Storage::Classes(),
588                                ast::Linkage::C
589                        )
590                );
591        }
592
593        return decl;
594}
595
596void CallAdapter::previsit( ast::TypeDecl const * decl ) {
597        addToTypeVarMap( decl, scopeTypeVars );
598}
599
600void CallAdapter::previsit( ast::CommaExpr const * expr ) {
601        // Attempting to find application expressions that were mutated by the
602        // copy constructor passes to use an explicit return variable, so that
603        // the variable can be reused as a parameter to the call rather than
604        // creating a new temporary variable. Previously this step was an
605        // optimization, but with the introduction of tuples and UniqueExprs,
606        // it is necessary to ensure that they use the same variable.
607        // Essentially, looking for pattern:
608        // (x=f(...), x)
609        // To compound the issue, the right side can be *x, etc.
610        // because of lvalue-returning functions
611        if ( auto assign = expr->arg1.as<ast::UntypedExpr>() ) {
612                if ( CodeGen::isAssignment( ast::getFunctionName( assign ) ) ) {
613                        assert( 2 == assign->args.size() );
614                        if ( auto app = assign->args.back().as<ast::ApplicationExpr>() ) {
615                                // First argument is assignable, so it must be an lvalue,
616                                // so it should be legal to takes its address.
617                                retVals.insert_or_assign( app, assign->args.front() );
618                        }
619                }
620        }
621}
622
623ast::Expr const * CallAdapter::postvisit( ast::ApplicationExpr const * expr ) {
624        assert( expr->func->result );
625        ast::FunctionType const * function = getFunctionType( expr->func->result );
626        assertf( function, "ApplicationExpr has non-function type %s",
627                        toCString( expr->func->result ) );
628
629        if ( auto newExpr = handleIntrinsics( expr ) ) {
630                return newExpr;
631        }
632
633        ast::ApplicationExpr * mutExpr = ast::mutate( expr );
634        ast::Expr const * ret = expr;
635
636        // TODO: This entire section should probably be refactored to do less
637        // pushing to the front/middle of a vector.
638        ptrdiff_t initArgCount = mutExpr->args.size();
639
640        TypeVarMap exprTypeVars;
641        // TODO: Should this take into account the variables already bound in
642        // scopeTypeVars ([ex] remove them from exprTypeVars)?
643        makeTypeVarMap( function, exprTypeVars );
644        auto dynRetType = isDynRet( function, exprTypeVars );
645
646        // NOTE: addDynRetParam needs to know the actual (generated) return type
647        // so it can make a temporary variable, so pass the result type form the
648        // `expr` `passTypeVars` needs to know the program-text return type ([ex]
649        // the distinction between _conc_T30 and T3(int)) concRetType may not be
650        // a good name in one or both of these places.
651        if ( dynRetType ) {
652                ast::Type const * result = mutExpr->result;
653                ast::Type const * concRetType = result->isVoid() ? nullptr : result;
654                // [Comment from before translation.]
655                // Used to use dynRetType instead of concRetType.
656                ret = addDynRetParam( mutExpr, concRetType );
657        } else if ( needsAdapter( function, scopeTypeVars )
658                        && !needsAdapter( function, exprTypeVars ) ) {
659                // Change the application so it calls the adapter rather than the
660                // passed function.
661                ret = applyAdapter( mutExpr, function );
662        }
663
664        assert( typeSubs );
665        ast::vector<ast::Expr>::iterator argIt =
666                passTypeVars( mutExpr, function );
667        addInferredParams( mutExpr, argIt, function, exprTypeVars );
668
669        argIt = mutExpr->args.begin();
670        std::advance( argIt, ( mutExpr->args.size() - initArgCount ) );
671
672        boxParams( mutExpr, argIt, function, exprTypeVars );
673        passAdapters( mutExpr, function, exprTypeVars );
674
675        return ret;
676}
677
678bool isPolyDeref( ast::UntypedExpr const * expr,
679                TypeVarMap const & typeVars,
680                ast::TypeSubstitution const * typeSubs ) {
681        if ( expr->result && isPolyType( expr->result, typeVars, typeSubs ) ) {
682                if ( auto name = expr->func.as<ast::NameExpr>() ) {
683                        if ( "*?" == name->name ) {
684                                return true;
685                        }
686                }
687        }
688        return false;
689}
690
691ast::Expr const * CallAdapter::postvisit( ast::UntypedExpr const * expr ) {
692        if ( isPolyDeref( expr, scopeTypeVars, typeSubs ) ) {
693                return expr->args.front();
694        }
695        return expr;
696}
697
698void CallAdapter::previsit( ast::AddressExpr const * ) {
699        visit_children = false;
700}
701
702ast::Expr const * CallAdapter::postvisit( ast::AddressExpr const * expr ) {
703        assert( expr->arg->result );
704        assert( !expr->arg->result->isVoid() );
705
706        bool doesNeedAdapter = false;
707        if ( auto un = expr->arg.as<ast::UntypedExpr>() ) {
708                if ( isPolyDeref( un, scopeTypeVars, typeSubs ) ) {
709                        if ( auto app = un->args.front().as<ast::ApplicationExpr>() ) {
710                                assert( app->func->result );
711                                auto function = getFunctionType( app->func->result );
712                                assert( function );
713                                doesNeedAdapter = needsAdapter( function, scopeTypeVars );
714                        }
715                }
716        }
717        // isPolyType check needs to happen before mutating expr arg,
718        // so pull it forward out of the if condition.
719        expr = ast::mutate_field( expr, &ast::AddressExpr::arg,
720                        expr->arg->accept( *visitor ) );
721        // But must happen after mutate, since argument might change
722        // (ex. intrinsic *?, ?[?]) re-evaluate above comment.
723        bool polyType = isPolyType( expr->arg->result, scopeTypeVars, typeSubs );
724        if ( polyType || doesNeedAdapter ) {
725                ast::Expr * ret = ast::mutate( expr->arg.get() );
726                ret->result = ast::deepCopy( expr->result );
727                return ret;
728        } else {
729                return expr;
730        }
731}
732
733ast::ReturnStmt const * CallAdapter::previsit( ast::ReturnStmt const * stmt ) {
734        // Since retval is set when the return type is dynamic, this function
735        // should have been converted to void return & out parameter.
736        if ( retval && stmt->expr ) {
737                assert( stmt->expr->result );
738                assert( !stmt->expr->result->isVoid() );
739                return ast::mutate_field( stmt, &ast::ReturnStmt::expr, nullptr );
740        }
741        return stmt;
742}
743
744void CallAdapter::beginScope() {
745        adapters.beginScope();
746}
747
748void CallAdapter::endScope() {
749        adapters.endScope();
750}
751
752/// Find instances of polymorphic type parameters.
753struct PolyFinder {
754        TypeVarMap const & typeVars;
755        bool result = false;
756        PolyFinder( TypeVarMap const & tvs ) : typeVars( tvs ) {}
757
758        void previsit( ast::TypeInstType const * type ) {
759                if ( isPolyType( type, typeVars ) ) result = true;
760        }
761};
762
763/// True if these is an instance of a polymorphic type parameter in the type.
764bool hasPolymorphism( ast::Type const * type, TypeVarMap const & typeVars ) {
765        return ast::Pass<PolyFinder>::read( type, typeVars );
766}
767
768ast::vector<ast::Expr>::iterator CallAdapter::passTypeVars(
769                ast::ApplicationExpr * expr,
770                ast::FunctionType const * function ) {
771        assert( typeSubs );
772        ast::vector<ast::Expr>::iterator arg = expr->args.begin();
773        // Pass size/align for type variables.
774        for ( ast::ptr<ast::TypeInstType> const & typeVar : function->forall ) {
775                if ( !typeVar->base->isComplete() ) continue;
776                ast::Type const * concrete = typeSubs->lookup( typeVar );
777                if ( !concrete ) {
778                        // Should this be an assertion?
779                        SemanticError( expr, toString( typeSubs,
780                                "\nunbound type variable: ", typeVar->typeString(),
781                                " in application " ) );
782                }
783                arg = expr->args.insert( arg,
784                        new ast::SizeofExpr( expr->location, ast::deepCopy( concrete ) ) );
785                arg++;
786                arg = expr->args.insert( arg,
787                        new ast::AlignofExpr( expr->location, ast::deepCopy( concrete ) ) );
788                arg++;
789        }
790        return arg;
791}
792
793ast::Expr const * CallAdapter::addRetParam(
794                ast::ApplicationExpr * expr, ast::Type const * retType ) {
795        // Create temporary to hold return value of polymorphic function and
796        // produce that temporary as a result using a comma expression.
797        assert( retType );
798
799        ast::Expr * paramExpr = nullptr;
800        // Try to use existing return value parameter if it exists,
801        // otherwise create a new temporary.
802        if ( retVals.count( expr ) ) {
803                paramExpr = ast::deepCopy( retVals[ expr ] );
804        } else {
805                auto newObj = makeTemporary( expr->location, ast::deepCopy( retType ) );
806                paramExpr = new ast::VariableExpr( expr->location, newObj );
807        }
808        ast::Expr * retExpr = ast::deepCopy( paramExpr );
809
810        // If the type of the temporary is not polpmorphic, box temporary by
811        // taking its address; otherwise the temporary is already boxed and can
812        // be used directly.
813        if ( !isPolyType( paramExpr->result, scopeTypeVars, typeSubs ) ) {
814                paramExpr = new ast::AddressExpr( paramExpr->location, paramExpr );
815        }
816        // Add argument to function call.
817        expr->args.insert( expr->args.begin(), paramExpr );
818        // Build a comma expression to call the function and return a value.
819        ast::CommaExpr * comma = new ast::CommaExpr(
820                expr->location, expr, retExpr );
821        comma->env = expr->env;
822        expr->env = nullptr;
823        return comma;
824}
825
826ast::Expr const * CallAdapter::addDynRetParam(
827                ast::ApplicationExpr * expr, ast::Type const * polyType ) {
828        assert( typeSubs );
829        ast::Type const * concrete = replaceWithConcrete( polyType, *typeSubs );
830        // Add out-parameter for return value.
831        return addRetParam( expr, concrete );
832}
833
834ast::Expr const * CallAdapter::applyAdapter(
835                ast::ApplicationExpr * expr,
836                ast::FunctionType const * function ) {
837        ast::Expr const * ret = expr;
838        if ( isDynRet( function, scopeTypeVars ) ) {
839                ret = addRetParam( expr, function->returns.front() );
840        }
841        std::string mangleName = mangleAdapterName( function, scopeTypeVars );
842        std::string adapterName = makeAdapterName( mangleName );
843
844        // Cast adaptee to `void (*)()`, since it may have any type inside a
845        // polymorphic function.
846        ast::Type const * adapteeType = new ast::PointerType(
847                new ast::FunctionType( ast::VariableArgs ) );
848        expr->args.insert( expr->args.begin(),
849                new ast::CastExpr( expr->location, expr->func, adapteeType ) );
850        // The result field is never set on NameExpr. / Now it is.
851        auto head = new ast::NameExpr( expr->location, adapterName );
852        head->result = ast::deepCopy( adapteeType );
853        expr->func = head;
854
855        return ret;
856}
857
858/// Cast parameters to polymorphic functions so that types are replaced with
859/// `void *` if they are type parameters in the formal type.
860/// This gets rid of warnings from gcc.
861void addCast(
862                ast::ptr<ast::Expr> & actual,
863                ast::Type const * formal,
864                TypeVarMap const & typeVars ) {
865        // Type contains polymorphism, but isn't exactly a polytype, in which
866        // case it has some real actual type (ex. unsigned int) and casting to
867        // `void *` is wrong.
868        if ( hasPolymorphism( formal, typeVars )
869                        && !isPolyType( formal, typeVars ) ) {
870                ast::Type const * newType = ast::deepCopy( formal );
871                newType = scrubTypeVars( newType, typeVars );
872                actual = new ast::CastExpr( actual->location, actual, newType );
873        }
874}
875
876void CallAdapter::boxParam( ast::ptr<ast::Expr> & arg,
877                ast::Type const * param, TypeVarMap const & exprTypeVars ) {
878        assertf( arg->result, "arg does not have result: %s", toCString( arg ) );
879        addCast( arg, param, exprTypeVars );
880        if ( !needsBoxing( param, arg->result, exprTypeVars, typeSubs ) ) {
881                return;
882        }
883        CodeLocation const & location = arg->location;
884
885        if ( arg->get_lvalue() ) {
886                // The argument expression may be CFA lvalue, but not C lvalue,
887                // so apply generalizedLvalue transformations.
888                // if ( auto var = dynamic_cast<ast::VariableExpr const *>( arg ) ) {
889                //  if ( dynamic_cast<ast::ArrayType const *>( varExpr->var->get_type() ) ){
890                //      // temporary hack - don't box arrays, because &arr is not the same as &arr[0]
891                //      return;
892                //  }
893                // }
894                arg = generalizedLvalue( new ast::AddressExpr( arg->location, arg ) );
895                if ( !ResolvExpr::typesCompatible( param, arg->result ) ) {
896                        // Silence warnings by casting boxed parameters when the actually
897                        // type does not match up with the formal type.
898                        arg = new ast::CastExpr( location, arg, ast::deepCopy( param ) );
899                }
900        } else {
901                // Use type computed in unification to declare boxed variables.
902                ast::ptr<ast::Type> newType = ast::deepCopy( param );
903                if ( typeSubs ) typeSubs->apply( newType );
904                ast::ObjectDecl * newObj = makeTemporary( location, newType );
905                auto assign = ast::UntypedExpr::createCall( location, "?=?", {
906                        new ast::VariableExpr( location, newObj ),
907                        arg,
908                } );
909                stmtsToAddBefore.push_back( new ast::ExprStmt( location, assign ) );
910                arg = new ast::AddressExpr(
911                        new ast::VariableExpr( location, newObj ) );
912        }
913}
914
915void CallAdapter::boxParams(
916                ast::ApplicationExpr const * expr,
917                ast::vector<ast::Expr>::iterator arg,
918                ast::FunctionType const * function,
919                const TypeVarMap & typeVars ) {
920        for ( auto param : function->params ) {
921                assertf( arg != expr->args.end(),
922                        "boxParams: missing argument for param %s to %s in %s",
923                        toCString( param ), toCString( function ), toCString( expr ) );
924                boxParam( *arg, param, typeVars );
925                ++arg;
926        }
927}
928
929void CallAdapter::addInferredParams(
930                ast::ApplicationExpr * expr,
931                ast::vector<ast::Expr>::iterator arg,
932                ast::FunctionType const * functionType,
933                TypeVarMap const & typeVars ) {
934        ast::vector<ast::Expr>::iterator cur = arg;
935        for ( auto assertion : functionType->assertions ) {
936                auto inferParam = expr->inferred.inferParams().find(
937                        assertion->var->uniqueId );
938                assertf( inferParam != expr->inferred.inferParams().end(),
939                        "addInferredParams missing inferred parameter: %s in: %s",
940                        toCString( assertion ), toCString( expr ) );
941                ast::ptr<ast::Expr> newExpr = ast::deepCopy( inferParam->second.expr );
942                boxParam( newExpr, assertion->result, typeVars );
943                cur = expr->args.insert( cur, newExpr.release() );
944                ++cur;
945        }
946}
947
948/// Modifies the ApplicationExpr to accept adapter functions for its
949/// assertion and parameters, declares the required adapters.
950void CallAdapter::passAdapters(
951                ast::ApplicationExpr * expr,
952                ast::FunctionType const * type,
953                const TypeVarMap & exprTypeVars ) {
954        // Collect a list of function types passed as parameters or implicit
955        // parameters (assertions).
956        ast::vector<ast::Type> const & paramList = type->params;
957        ast::vector<ast::FunctionType> functions;
958
959        for ( ast::ptr<ast::VariableExpr> const & assertion : type->assertions ) {
960                findFunction( assertion->result, functions, exprTypeVars, needsAdapter );
961        }
962        for ( ast::ptr<ast::Type> const & arg : paramList ) {
963                findFunction( arg, functions, exprTypeVars, needsAdapter );
964        }
965
966        // Parameter function types for which an appropriate adapter has been
967        // generated. We cannot use the types after applying substitutions,
968        // since two different parameter types may be unified to the same type.
969        std::set<std::string> adaptersDone;
970
971        CodeLocation const & location = expr->location;
972
973        for ( ast::ptr<ast::FunctionType> const & funcType : functions ) {
974                std::string mangleName = Mangle::mangle( funcType );
975
976                // Only attempt to create an adapter or pass one as a parameter if we
977                // haven't already done so for this pre-substitution parameter
978                // function type.
979                // The second part of the result if is if the element was inserted.
980                if ( !adaptersDone.insert( mangleName ).second ) continue;
981
982                // Apply substitution to type variables to figure out what the
983                // adapter's type should look like. (Copy to make the release safe.)
984                assert( typeSubs );
985                auto result = typeSubs->apply( ast::deepCopy( funcType ) );
986                ast::FunctionType * realType = ast::mutate( result.node.release() );
987                mangleName = Mangle::mangle( realType );
988                mangleName += makePolyMonoSuffix( funcType, exprTypeVars );
989
990                // Check if the adapter has already been created, or has to be.
991                using AdapterIter = decltype(adapters)::iterator;
992                AdapterIter adapter = adapters.find( mangleName );
993                if ( adapter == adapters.end() ) {
994                        ast::FunctionDecl * newAdapter = makeAdapter(
995                                funcType, realType, mangleName, exprTypeVars, location );
996                        std::pair<AdapterIter, bool> answer =
997                                adapters.insert( mangleName, newAdapter );
998                        adapter = answer.first;
999                        stmtsToAddBefore.push_back(
1000                                new ast::DeclStmt( location, newAdapter ) );
1001                }
1002                assert( adapter != adapters.end() );
1003
1004                // Add the approprate adapter as a parameter.
1005                expr->args.insert( expr->args.begin(),
1006                        new ast::VariableExpr( location, adapter->second ) );
1007        }
1008}
1009
1010// Parameter and argument may be used wrong around here.
1011ast::Expr * makeAdapterArg(
1012                ast::DeclWithType const * param,
1013                ast::Type const * arg,
1014                ast::Type const * realParam,
1015                TypeVarMap const & typeVars,
1016                CodeLocation const & location ) {
1017        assert( param );
1018        assert( arg );
1019        assert( realParam );
1020        if ( isPolyType( realParam, typeVars ) && !isPolyType( arg ) ) {
1021                ast::UntypedExpr * deref = ast::UntypedExpr::createDeref(
1022                        location,
1023                        new ast::CastExpr( location,
1024                                new ast::VariableExpr( location, param ),
1025                                new ast::PointerType( ast::deepCopy( arg ) )
1026                        )
1027                );
1028                deref->result = ast::deepCopy( arg );
1029                return deref;
1030        }
1031        return new ast::VariableExpr( location, param );
1032}
1033
1034// This seems to be one of the problematic functions.
1035void addAdapterParams(
1036                ast::ApplicationExpr * adaptee,
1037                ast::vector<ast::Type>::const_iterator arg,
1038                ast::vector<ast::DeclWithType>::iterator param,
1039                ast::vector<ast::DeclWithType>::iterator paramEnd,
1040                ast::vector<ast::Type>::const_iterator realParam,
1041                TypeVarMap const & typeVars,
1042                CodeLocation const & location ) {
1043        UniqueName paramNamer( "_p" );
1044        for ( ; param != paramEnd ; ++param, ++arg, ++realParam ) {
1045                if ( "" == (*param)->name ) {
1046                        auto mutParam = (*param).get_and_mutate();
1047                        mutParam->name = paramNamer.newName();
1048                        mutParam->linkage = ast::Linkage::C;
1049                }
1050                adaptee->args.push_back(
1051                        makeAdapterArg( *param, *arg, *realParam, typeVars, location ) );
1052        }
1053}
1054
1055ast::FunctionDecl * CallAdapter::makeAdapter(
1056                ast::FunctionType const * adaptee,
1057                ast::FunctionType const * realType,
1058                std::string const & mangleName,
1059                TypeVarMap const & typeVars,
1060                CodeLocation const & location ) const {
1061        ast::FunctionType * adapterType = makeAdapterType( adaptee, typeVars );
1062        adapterType = ast::mutate( scrubTypeVars( adapterType, typeVars ) );
1063
1064        // Some of these names will be overwritten, but it gives a default.
1065        UniqueName pNamer( "_param" );
1066        UniqueName rNamer( "_ret" );
1067
1068        bool first = true;
1069
1070        ast::FunctionDecl * adapterDecl = new ast::FunctionDecl( location,
1071                makeAdapterName( mangleName ),
1072                {}, // forall
1073                {}, // assertions
1074                map_range<ast::vector<ast::DeclWithType>>( adapterType->params,
1075                                [&pNamer, &location, &first]( ast::ptr<ast::Type> const & param ) {
1076                        // [Trying to make the generated code match exactly more often.]
1077                        if ( first ) {
1078                                first = false;
1079                                return new ast::ObjectDecl( location, "_adaptee", param );
1080                        }
1081                        return new ast::ObjectDecl( location, pNamer.newName(), param );
1082                } ),
1083                map_range<ast::vector<ast::DeclWithType>>( adapterType->returns,
1084                                [&rNamer, &location]( ast::ptr<ast::Type> const & retval ) {
1085                        return new ast::ObjectDecl( location, rNamer.newName(), retval );
1086                } ),
1087                nullptr, // stmts
1088                {}, // storage
1089                ast::Linkage::C
1090        );
1091
1092        ast::DeclWithType * adapteeDecl =
1093                adapterDecl->params.front().get_and_mutate();
1094        adapteeDecl->name = "_adaptee";
1095
1096        // Do not carry over attributes to real type parameters/return values.
1097        auto mutRealType = ast::mutate( realType );
1098        for ( ast::ptr<ast::Type> & decl : mutRealType->params ) {
1099                if ( decl->attributes.empty() ) continue;
1100                auto mut = ast::mutate( decl.get() );
1101                mut->attributes.clear();
1102                decl = mut;
1103        }
1104        for ( ast::ptr<ast::Type> & decl : mutRealType->returns ) {
1105                if ( decl->attributes.empty() ) continue;
1106                auto mut = ast::mutate( decl.get() );
1107                mut->attributes.clear();
1108                decl = mut;
1109        }
1110        realType = mutRealType;
1111
1112        ast::ApplicationExpr * adapteeApp = new ast::ApplicationExpr( location,
1113                new ast::CastExpr( location,
1114                        new ast::VariableExpr( location, adapteeDecl ),
1115                        new ast::PointerType( realType )
1116                )
1117        );
1118
1119        for ( auto group : group_iterate( realType->assertions,
1120                        adapterType->assertions, adaptee->assertions ) ) {
1121                auto assertArg = std::get<0>( group );
1122                auto assertParam = std::get<1>( group );
1123                auto assertReal = std::get<2>( group );
1124                adapteeApp->args.push_back( makeAdapterArg(
1125                        assertParam->var, assertArg->var->get_type(),
1126                        assertReal->var->get_type(), typeVars, location
1127                ) );
1128        }
1129
1130        ast::vector<ast::Type>::const_iterator
1131                arg = realType->params.begin(),
1132                param = adapterType->params.begin(),
1133                realParam = adaptee->params.begin();
1134        ast::vector<ast::DeclWithType>::iterator
1135                paramDecl = adapterDecl->params.begin();
1136        // Skip adaptee parameter in the adapter type.
1137        ++param;
1138        ++paramDecl;
1139
1140        ast::Stmt * bodyStmt;
1141        // Returns void/nothing.
1142        if ( realType->returns.empty() ) {
1143                addAdapterParams( adapteeApp, arg, paramDecl, adapterDecl->params.end(),
1144                        realParam, typeVars, location );
1145                bodyStmt = new ast::ExprStmt( location, adapteeApp );
1146        // Returns a polymorphic type.
1147        } else if ( isDynType( adaptee->returns.front(), typeVars ) ) {
1148                ast::UntypedExpr * assign = new ast::UntypedExpr( location,
1149                        new ast::NameExpr( location, "?=?" ) );
1150                ast::UntypedExpr * deref = ast::UntypedExpr::createDeref( location,
1151                        new ast::CastExpr( location,
1152                                new ast::VariableExpr( location, *paramDecl++ ),
1153                                new ast::PointerType(
1154                                        ast::deepCopy( realType->returns.front() ) ) ) );
1155                assign->args.push_back( deref );
1156                addAdapterParams( adapteeApp, arg, paramDecl, adapterDecl->params.end(),
1157                        realParam, typeVars, location );
1158                assign->args.push_back( adapteeApp );
1159                bodyStmt = new ast::ExprStmt( location, assign );
1160        // Adapter for a function that returns a monomorphic value.
1161        } else {
1162                addAdapterParams( adapteeApp, arg, paramDecl, adapterDecl->params.end(),
1163                                realParam, typeVars, location );
1164                bodyStmt = new ast::ReturnStmt( location, adapteeApp );
1165        }
1166
1167        adapterDecl->stmts = new ast::CompoundStmt( location, { bodyStmt } );
1168        return adapterDecl;
1169}
1170
1171ast::Expr const * makeIncrDecrExpr(
1172                CodeLocation const & location,
1173                ast::ApplicationExpr const * expr,
1174                ast::Type const * polyType,
1175                bool isIncr ) {
1176        ast::NameExpr * opExpr =
1177                        new ast::NameExpr( location, isIncr ? "?+=?" : "?-=?" );
1178        ast::UntypedExpr * addAssign = new ast::UntypedExpr( location, opExpr );
1179        if ( auto address = expr->args.front().as<ast::AddressExpr>() ) {
1180                addAssign->args.push_back( address->arg );
1181        } else {
1182                addAssign->args.push_back( expr->args.front() );
1183        }
1184        addAssign->args.push_back( new ast::NameExpr( location,
1185                sizeofName( Mangle::mangleType( polyType ) ) ) );
1186        addAssign->result = ast::deepCopy( expr->result );
1187        addAssign->env = expr->env ? expr->env : addAssign->env;
1188        return addAssign;
1189}
1190
1191/// Handles intrinsic functions for postvisit ApplicationExpr.
1192ast::Expr const * CallAdapter::handleIntrinsics(
1193                ast::ApplicationExpr const * expr ) {
1194        auto varExpr = expr->func.as<ast::VariableExpr>();
1195        if ( !varExpr || varExpr->var->linkage != ast::Linkage::Intrinsic ) {
1196                return nullptr;
1197        }
1198        std::string const & varName = varExpr->var->name;
1199
1200        // Index Intrinsic:
1201        if ( "?[?]" == varName ) {
1202                assert( expr->result );
1203                assert( 2 == expr->args.size() );
1204
1205                ast::Type const * baseType1 =
1206                        isPolyPtr( expr->args.front()->result, scopeTypeVars, typeSubs );
1207                ast::Type const * baseType2 =
1208                        isPolyPtr( expr->args.back()->result, scopeTypeVars, typeSubs );
1209                // If neither argument is a polymorphic pointer, do nothing.
1210                if ( !baseType1 && !baseType2 ) {
1211                        return expr;
1212                }
1213                // The arguments cannot both be polymorphic pointers.
1214                assert( !baseType1 || !baseType2 );
1215                // (So exactly one of the arguments is a polymorphic pointer.)
1216
1217                CodeLocation const & location = expr->location;
1218                CodeLocation const & location1 = expr->args.front()->location;
1219                CodeLocation const & location2 = expr->args.back()->location;
1220
1221                ast::UntypedExpr * ret = new ast::UntypedExpr( location,
1222                                new ast::NameExpr( location, "?+?" ) );
1223                if ( baseType1 ) {
1224                        auto multiply = ast::UntypedExpr::createCall( location2, "?*?", {
1225                                expr->args.back(),
1226                                new ast::SizeofExpr( location1, deepCopy( baseType1 ) ),
1227                        } );
1228                        ret->args.push_back( expr->args.front() );
1229                        ret->args.push_back( multiply );
1230                } else {
1231                        assert( baseType2 );
1232                        auto multiply = ast::UntypedExpr::createCall( location1, "?*?", {
1233                                expr->args.front(),
1234                                new ast::SizeofExpr( location2, deepCopy( baseType2 ) ),
1235                        } );
1236                        ret->args.push_back( multiply );
1237                        ret->args.push_back( expr->args.back() );
1238                }
1239                ret->result = ast::deepCopy( expr->result );
1240                ret->env = expr->env ? expr->env : ret->env;
1241                return ret;
1242        // Dereference Intrinsic:
1243        } else if ( "*?" == varName ) {
1244                assert( expr->result );
1245                assert( 1 == expr->args.size() );
1246
1247                // If this isn't for a poly type, then do nothing.
1248                if ( !isPolyType( expr->result, scopeTypeVars, typeSubs ) ) {
1249                        return expr;
1250                }
1251
1252                // Remove dereference from polymorphic types since they are boxed.
1253                ast::Expr * ret = ast::deepCopy( expr->args.front() );
1254                // Fix expression type to remove pointer.
1255                ret->result = expr->result;
1256                ret->env = expr->env ? expr->env : ret->env;
1257                return ret;
1258        // Post-Increment/Decrement Intrinsics:
1259        } else if ( "?++" == varName || "?--" == varName ) {
1260                assert( expr->result );
1261                assert( 1 == expr->args.size() );
1262
1263                ast::Type const * baseType =
1264                        isPolyType( expr->result, scopeTypeVars, typeSubs );
1265                if ( nullptr == baseType ) {
1266                        return expr;
1267                }
1268                ast::Type * tempType = ast::deepCopy( expr->result );
1269                if ( typeSubs ) {
1270                        auto result = typeSubs->apply( tempType );
1271                        tempType = ast::mutate( result.node.release() );
1272                }
1273                CodeLocation const & location = expr->location;
1274                ast::ObjectDecl * newObj = makeTemporary( location, tempType );
1275                ast::VariableExpr * tempExpr =
1276                        new ast::VariableExpr( location, newObj );
1277                ast::UntypedExpr * assignExpr = new ast::UntypedExpr( location,
1278                        new ast::NameExpr( location, "?=?" ) );
1279                assignExpr->args.push_back( ast::deepCopy( tempExpr ) );
1280                if ( auto address = expr->args.front().as<ast::AddressExpr>() ) {
1281                        assignExpr->args.push_back( ast::deepCopy( address->arg ) );
1282                } else {
1283                        assignExpr->args.push_back( ast::deepCopy( expr->args.front() ) );
1284                }
1285                return new ast::CommaExpr( location,
1286                        new ast::CommaExpr( location,
1287                                assignExpr,
1288                                makeIncrDecrExpr( location, expr, baseType, "?++" == varName )
1289                        ),
1290                        tempExpr
1291                );
1292        // Pre-Increment/Decrement Intrinsics:
1293        } else if ( "++?" == varName || "--?" == varName ) {
1294                assert( expr->result );
1295                assert( 1 == expr->args.size() );
1296
1297                ast::Type const * baseType =
1298                        isPolyType( expr->result, scopeTypeVars, typeSubs );
1299                if ( nullptr == baseType ) {
1300                        return expr;
1301                }
1302                return makeIncrDecrExpr(
1303                        expr->location, expr, baseType, "++?" == varName );
1304        // Addition and Subtration Intrinsics:
1305        } else if ( "?+?" == varName || "?-?" == varName ) {
1306                assert( expr->result );
1307                assert( 2 == expr->args.size() );
1308
1309                auto baseType1 =
1310                        isPolyPtr( expr->args.front()->result, scopeTypeVars, typeSubs );
1311                auto baseType2 =
1312                        isPolyPtr( expr->args.back()->result, scopeTypeVars, typeSubs );
1313
1314                CodeLocation const & location = expr->location;
1315                CodeLocation const & location1 = expr->args.front()->location;
1316                CodeLocation const & location2 = expr->args.back()->location;
1317                // LHS op RHS -> (LHS op RHS) / sizeof(LHS)
1318                if ( baseType1 && baseType2 ) {
1319                        auto divide = ast::UntypedExpr::createCall( location, "?/?", {
1320                                expr,
1321                                new ast::SizeofExpr( location, deepCopy( baseType1 ) ),
1322                        } );
1323                        if ( expr->env ) divide->env = expr->env;
1324                        return divide;
1325                // LHS op RHS -> LHS op (RHS * sizeof(LHS))
1326                } else if ( baseType1 ) {
1327                        auto multiply = ast::UntypedExpr::createCall( location2, "?*?", {
1328                                expr->args.back(),
1329                                new ast::SizeofExpr( location1, deepCopy( baseType1 ) ),
1330                        } );
1331                        return ast::mutate_field_index(
1332                                expr, &ast::ApplicationExpr::args, 1, multiply );
1333                // LHS op RHS -> (LHS * sizeof(RHS)) op RHS
1334                } else if ( baseType2 ) {
1335                        auto multiply = ast::UntypedExpr::createCall( location1, "?*?", {
1336                                expr->args.front(),
1337                                new ast::SizeofExpr( location2, deepCopy( baseType2 ) ),
1338                        } );
1339                        return ast::mutate_field_index(
1340                                expr, &ast::ApplicationExpr::args, 0, multiply );
1341                }
1342        // Addition and Subtration Relative Assignment Intrinsics:
1343        } else if ( "?+=?" == varName || "?-=?" == varName ) {
1344                assert( expr->result );
1345                assert( 2 == expr->args.size() );
1346
1347                CodeLocation const & location1 = expr->args.front()->location;
1348                CodeLocation const & location2 = expr->args.back()->location;
1349                auto baseType = isPolyPtr( expr->result, scopeTypeVars, typeSubs );
1350                // LHS op RHS -> LHS op (RHS * sizeof(LHS))
1351                if ( baseType ) {
1352                        auto multiply = ast::UntypedExpr::createCall( location2, "?*?", {
1353                                expr->args.back(),
1354                                new ast::SizeofExpr( location1, deepCopy( baseType ) ),
1355                        } );
1356                        return ast::mutate_field_index(
1357                                expr, &ast::ApplicationExpr::args, 1, multiply );
1358                }
1359        }
1360        return expr;
1361}
1362
1363ast::ObjectDecl * CallAdapter::makeTemporary(
1364                CodeLocation const & location, ast::Type const * type ) {
1365        auto newObj = new ast::ObjectDecl( location, tmpNamer.newName(), type );
1366        stmtsToAddBefore.push_back( new ast::DeclStmt( location, newObj ) );
1367        return newObj;
1368}
1369
1370// --------------------------------------------------------------------------
1371/// Modifies declarations to accept implicit parameters.
1372/// * Move polymorphic returns in function types to pointer-type parameters.
1373/// * Adds type size and assertion parameters to parameter lists.
1374struct DeclAdapter final {
1375        ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl );
1376        ast::FunctionDecl const * postvisit( ast::FunctionDecl const * decl );
1377private:
1378        void addAdapters( ast::FunctionDecl * decl, TypeVarMap & localTypeVars );
1379};
1380
1381ast::ObjectDecl * makeObj(
1382                CodeLocation const & location, std::string const & name ) {
1383        // The size/align parameters may be unused, so add the unused attribute.
1384        return new ast::ObjectDecl( location, name,
1385                makeLayoutCType(),
1386                nullptr, ast::Storage::Classes(), ast::Linkage::C, nullptr,
1387                { new ast::Attribute( "unused" ) } );
1388}
1389
1390/// A modified and specialized version of ast::add_qualifiers.
1391ast::Type const * addConst( ast::Type const * type ) {
1392        ast::CV::Qualifiers cvq = { ast::CV::Const };
1393        if ( ( type->qualifiers & cvq ) != 0 ) return type;
1394        auto mutType = ast::mutate( type );
1395        mutType->qualifiers |= cvq;
1396        return mutType;
1397}
1398
1399ast::FunctionDecl const * DeclAdapter::previsit( ast::FunctionDecl const * decl ) {
1400        TypeVarMap localTypeVars;
1401        makeTypeVarMap( decl, localTypeVars );
1402
1403        auto mutDecl = mutate( decl );
1404
1405        // Move polymorphic return type to parameter list.
1406        if ( isDynRet( mutDecl->type ) ) {
1407                auto ret = strict_dynamic_cast<ast::ObjectDecl *>(
1408                        mutDecl->returns.front().get_and_mutate() );
1409                ret->set_type( new ast::PointerType( ret->type ) );
1410                mutDecl->params.insert( mutDecl->params.begin(), ret );
1411                mutDecl->returns.erase( mutDecl->returns.begin() );
1412                ret->init = nullptr;
1413        }
1414
1415        // Add size/align and assertions for type parameters to parameter list.
1416        ast::vector<ast::DeclWithType> inferredParams;
1417        ast::vector<ast::DeclWithType> layoutParams;
1418        for ( ast::ptr<ast::TypeDecl> & typeParam : mutDecl->type_params ) {
1419                auto mutParam = mutate( typeParam.get() );
1420                // Add all size and alignment parameters to parameter list.
1421                if ( mutParam->isComplete() ) {
1422                        ast::TypeInstType paramType( mutParam );
1423                        std::string paramName = Mangle::mangleType( &paramType );
1424
1425                        auto sizeParam = makeObj( typeParam->location, sizeofName( paramName ) );
1426                        layoutParams.emplace_back( sizeParam );
1427
1428                        auto alignParam = makeObj( typeParam->location, alignofName( paramName ) );
1429                        layoutParams.emplace_back( alignParam );
1430                }
1431                // Assertions should be stored in the main list.
1432                assert( mutParam->assertions.empty() );
1433                typeParam = mutParam;
1434        }
1435        for ( ast::ptr<ast::DeclWithType> & assert : mutDecl->assertions ) {
1436                ast::DeclWithType * mutAssert = ast::mutate( assert.get() );
1437                // Assertion parameters may not be used in body,
1438                // pass along with unused attribute.
1439                mutAssert->attributes.push_back( new ast::Attribute( "unused" ) );
1440                mutAssert->set_type( addConst( mutAssert->get_type() ) );
1441                inferredParams.emplace_back( mutAssert );
1442        }
1443        mutDecl->assertions.clear();
1444
1445        // Prepend each argument group. From last group to first. addAdapters
1446        // does do the same, it just does it itself and see all other parameters.
1447        spliceBegin( mutDecl->params, inferredParams );
1448        spliceBegin( mutDecl->params, layoutParams );
1449        addAdapters( mutDecl, localTypeVars );
1450
1451        // Now have to update the type to match the declaration.
1452        ast::FunctionType * type = new ast::FunctionType(
1453                mutDecl->type->isVarArgs, mutDecl->type->qualifiers );
1454        // The forall clauses don't match until Eraser. The assertions are empty.
1455        for ( auto param : mutDecl->params ) {
1456                type->params.emplace_back( param->get_type() );
1457        }
1458        for ( auto retval : mutDecl->returns ) {
1459                type->returns.emplace_back( retval->get_type() );
1460        }
1461        mutDecl->type = type;
1462
1463        return mutDecl;
1464}
1465
1466ast::FunctionDecl const * DeclAdapter::postvisit(
1467                ast::FunctionDecl const * decl ) {
1468        ast::FunctionDecl * mutDecl = mutate( decl );
1469        if ( !mutDecl->returns.empty() && mutDecl->stmts
1470                        // Intrinsic functions won't be using the _retval so no need to
1471                        // generate it.
1472                        && mutDecl->linkage != ast::Linkage::Intrinsic
1473                        // Remove check for prefix once thunks properly use ctor/dtors.
1474                        && !isPrefix( mutDecl->name, "_thunk" )
1475                        && !isPrefix( mutDecl->name, "_adapter" ) ) {
1476                assert( 1 == mutDecl->returns.size() );
1477                ast::DeclWithType const * retval = mutDecl->returns.front();
1478                if ( "" == retval->name ) {
1479                        retval = ast::mutate_field(
1480                                retval, &ast::DeclWithType::name, "_retval" );
1481                        mutDecl->returns.front() = retval;
1482                }
1483                auto stmts = mutDecl->stmts.get_and_mutate();
1484                stmts->kids.push_front( new ast::DeclStmt( retval->location, retval ) );
1485                ast::DeclWithType * newRet = ast::deepCopy( retval );
1486                mutDecl->returns.front() = newRet;
1487        }
1488        // Errors should have been caught by this point, remove initializers from
1489        // parameters to allow correct codegen of default arguments.
1490        for ( ast::ptr<ast::DeclWithType> & param : mutDecl->params ) {
1491                if ( auto obj = param.as<ast::ObjectDecl>() ) {
1492                        param = ast::mutate_field( obj, &ast::ObjectDecl::init, nullptr );
1493                }
1494        }
1495        return mutDecl;
1496}
1497
1498void DeclAdapter::addAdapters(
1499                ast::FunctionDecl * mutDecl, TypeVarMap & localTypeVars ) {
1500        ast::vector<ast::FunctionType> functions;
1501        for ( ast::ptr<ast::DeclWithType> & arg : mutDecl->params ) {
1502                ast::Type const * type = arg->get_type();
1503                type = findAndReplaceFunction( type, functions, localTypeVars, needsAdapter );
1504                arg.get_and_mutate()->set_type( type );
1505        }
1506        std::set<std::string> adaptersDone;
1507        for ( ast::ptr<ast::FunctionType> const & func : functions ) {
1508                std::string mangleName = mangleAdapterName( func, localTypeVars );
1509                if ( adaptersDone.find( mangleName ) != adaptersDone.end() ) {
1510                        continue;
1511                }
1512                std::string adapterName = makeAdapterName( mangleName );
1513                // The adapter may not actually be used, so make sure it has unused.
1514                mutDecl->params.insert( mutDecl->params.begin(), new ast::ObjectDecl(
1515                        mutDecl->location, adapterName,
1516                        new ast::PointerType( makeAdapterType( func, localTypeVars ) ),
1517                        nullptr, {}, {}, nullptr,
1518                        { new ast::Attribute( "unused" ) } ) );
1519                adaptersDone.insert( adaptersDone.begin(), mangleName );
1520        }
1521}
1522
1523// --------------------------------------------------------------------------
1524// TODO: Ideally, there would be no floating nodes at all.
1525/// Corrects the floating nodes created in CallAdapter.
1526struct RewireAdapters final : public ast::WithGuards {
1527        ScopedMap<std::string, ast::ObjectDecl const *> adapters;
1528        void beginScope() { adapters.beginScope(); }
1529        void endScope() { adapters.endScope(); }
1530        void previsit( ast::FunctionDecl const * decl );
1531        ast::VariableExpr const * previsit( ast::VariableExpr const * expr );
1532};
1533
1534void RewireAdapters::previsit( ast::FunctionDecl const * decl ) {
1535        GuardScope( adapters );
1536        for ( ast::ptr<ast::DeclWithType> const & param : decl->params ) {
1537                if ( auto objectParam = param.as<ast::ObjectDecl>() ) {
1538                        adapters.insert( objectParam->name, objectParam );
1539                }
1540        }
1541}
1542
1543ast::VariableExpr const * RewireAdapters::previsit(
1544                ast::VariableExpr const * expr ) {
1545        // If the node is not floating, we can skip.
1546        if ( expr->var->isManaged() ) return expr;
1547        auto it = adapters.find( expr->var->name );
1548        assertf( it != adapters.end(), "Could not correct floating node." );
1549        return ast::mutate_field( expr, &ast::VariableExpr::var, it->second );
1550}
1551
1552// --------------------------------------------------------------------------
1553/// Inserts code to access polymorphic layout inforation.
1554/// * Replaces member and size/alignment/offsetof expressions on polymorphic
1555///   generic types with calculated expressions.
1556/// * Replaces member expressions for polymorphic types with calculated
1557///   add-field-offset-and-dereference.
1558/// * Calculates polymorphic offsetof expressions from offset array.
1559/// * Inserts dynamic calculation of polymorphic type layouts where needed.
1560struct PolyGenericCalculator final :
1561                public ast::WithConstTypeSubstitution,
1562                public ast::WithDeclsToAdd<>,
1563                public ast::WithGuards,
1564                public ast::WithStmtsToAdd<>,
1565                public ast::WithVisitorRef<PolyGenericCalculator> {
1566        PolyGenericCalculator();
1567
1568        void previsit( ast::FunctionDecl const * decl );
1569        void previsit( ast::TypedefDecl const * decl );
1570        void previsit( ast::TypeDecl const * decl );
1571        ast::Decl const * postvisit( ast::TypeDecl const * decl );
1572        ast::StructDecl const * previsit( ast::StructDecl const * decl );
1573        ast::UnionDecl const * previsit( ast::UnionDecl const * decl );
1574        ast::DeclStmt const * previsit( ast::DeclStmt const * stmt );
1575        ast::Expr const * postvisit( ast::MemberExpr const * expr );
1576        void previsit( ast::AddressExpr const * expr );
1577        ast::Expr const * postvisit( ast::AddressExpr const * expr );
1578        ast::Expr const * postvisit( ast::SizeofExpr const * expr );
1579        ast::Expr const * postvisit( ast::AlignofExpr const * expr );
1580        ast::Expr const * postvisit( ast::OffsetofExpr const * expr );
1581        ast::Expr const * postvisit( ast::OffsetPackExpr const * expr );
1582
1583        void beginScope();
1584        void endScope();
1585private:
1586        /// Makes a new variable in the current scope with the given name,
1587        /// type and optional initializer.
1588        ast::ObjectDecl * makeVar(
1589                        CodeLocation const & location, std::string const & name,
1590                        ast::Type const * type, ast::Init const * init = nullptr );
1591        /// Returns true if the type has a dynamic layout;
1592        /// such a layout will be stored in appropriately-named local variables
1593        /// when the function returns.
1594        bool findGeneric( CodeLocation const & location, ast::Type const * );
1595        /// Adds type parameters to the layout call; will generate the
1596        /// appropriate parameters if needed.
1597        void addSTypeParamsToLayoutCall(
1598                ast::UntypedExpr * layoutCall,
1599                const ast::vector<ast::Type> & otypeParams );
1600        /// Change the type of generic aggregate members to char[].
1601        void mutateMembers( ast::AggregateDecl * aggr );
1602        /// Returns the calculated sizeof expression for type, or nullptr for use
1603        /// C sizeof().
1604        ast::Expr const * genSizeof( CodeLocation const &, ast::Type const * );
1605        /// Enters a new scope for type-variables,
1606        /// adding the type variables from the provided type.
1607        void beginTypeScope( ast::Type const * );
1608
1609        /// The type variables and polymorphic parameters currently in scope.
1610        TypeVarMap scopeTypeVars;
1611        /// Set of generic type layouts known in the current scope,
1612        /// indexed by sizeofName.
1613        ScopedSet<std::string> knownLayouts;
1614        /// Set of non-generic types for which the offset array exists in the
1615        /// current scope, indexed by offsetofName.
1616        ScopedSet<std::string> knownOffsets;
1617        /// Namer for VLA (variable length array) buffers.
1618        UniqueName bufNamer;
1619        /// If the argument of an AddressExpr is MemberExpr, it is stored here.
1620        ast::MemberExpr const * addrMember = nullptr;
1621};
1622
1623PolyGenericCalculator::PolyGenericCalculator() :
1624        knownLayouts(), knownOffsets(), bufNamer( "_buf" )
1625{}
1626
1627/// Converts polymorphic type into a suitable monomorphic representation.
1628/// Currently: __attribute__((aligned(8) )) char[size_T];
1629ast::Type * polyToMonoType( CodeLocation const & location,
1630                ast::Type const * declType ) {
1631        auto charType = new ast::BasicType( ast::BasicType::Char );
1632        auto size = new ast::NameExpr( location,
1633                sizeofName( Mangle::mangleType( declType ) ) );
1634        auto aligned = new ast::Attribute( "aligned",
1635                { ast::ConstantExpr::from_int( location, 8 ) } );
1636        auto ret = new ast::ArrayType( charType, size,
1637                ast::VariableLen, ast::DynamicDim, ast::CV::Qualifiers() );
1638        ret->attributes.push_back( aligned );
1639        return ret;
1640}
1641
1642void PolyGenericCalculator::previsit( ast::FunctionDecl const * decl ) {
1643        GuardScope( *this );
1644        beginTypeScope( decl->type );
1645}
1646
1647void PolyGenericCalculator::previsit( ast::TypedefDecl const * decl ) {
1648        assertf( false, "All typedef declarations should be removed." );
1649        beginTypeScope( decl->base );
1650}
1651
1652void PolyGenericCalculator::previsit( ast::TypeDecl const * decl ) {
1653        addToTypeVarMap( decl, scopeTypeVars );
1654}
1655
1656ast::Decl const * PolyGenericCalculator::postvisit(
1657                ast::TypeDecl const * decl ) {
1658        ast::Type const * base = decl->base;
1659        if ( nullptr == base ) return decl;
1660
1661        // Add size/align variables for opaque type declarations.
1662        ast::TypeInstType inst( decl->name, decl );
1663        std::string typeName = Mangle::mangleType( &inst );
1664
1665        ast::ObjectDecl * sizeDecl = new ast::ObjectDecl( decl->location,
1666                sizeofName( typeName ), makeLayoutCType(),
1667                new ast::SingleInit( decl->location,
1668                        new ast::SizeofExpr( decl->location, deepCopy( base ) )
1669                )
1670        );
1671        ast::ObjectDecl * alignDecl = new ast::ObjectDecl( decl->location,
1672                alignofName( typeName ), makeLayoutCType(),
1673                new ast::SingleInit( decl->location,
1674                        new ast::AlignofExpr( decl->location, deepCopy( base ) )
1675                )
1676        );
1677
1678        // Ensure that the initializing sizeof/alignof exprs are properly mutated.
1679        sizeDecl->accept( *visitor );
1680        alignDecl->accept( *visitor );
1681
1682        // A little trick to replace this with two declarations.
1683        // Adding after makes sure that there is no conflict with adding stmts.
1684        declsToAddAfter.push_back( alignDecl );
1685        return sizeDecl;
1686}
1687
1688ast::StructDecl const * PolyGenericCalculator::previsit(
1689                ast::StructDecl const * decl ) {
1690        auto mutDecl = mutate( decl );
1691        mutateMembers( mutDecl );
1692        return mutDecl;
1693}
1694
1695ast::UnionDecl const * PolyGenericCalculator::previsit(
1696                ast::UnionDecl const * decl ) {
1697        auto mutDecl = mutate( decl );
1698        mutateMembers( mutDecl );
1699        return mutDecl;
1700}
1701
1702ast::DeclStmt const * PolyGenericCalculator::previsit( ast::DeclStmt const * stmt ) {
1703        ast::ObjectDecl const * decl = stmt->decl.as<ast::ObjectDecl>();
1704        if ( !decl || !findGeneric( decl->location, decl->type ) ) {
1705                return stmt;
1706        }
1707
1708        // Change initialization of a polymorphic value object to allocate via a
1709        // variable-length-array (alloca cannot be safely used in loops).
1710        ast::ObjectDecl * newBuf = new ast::ObjectDecl( decl->location,
1711                bufNamer.newName(),
1712                polyToMonoType( decl->location, decl->type ),
1713                nullptr, {}, ast::Linkage::C
1714        );
1715        stmtsToAddBefore.push_back( new ast::DeclStmt( stmt->location, newBuf ) );
1716
1717        // If the object has a cleanup attribute, the clean-up should be on the
1718        // buffer, not the pointer. [Perhaps this should be lifted?]
1719        auto matchAndMove = [newBuf]( ast::ptr<ast::Attribute> & attr ) {
1720                if ( "cleanup" == attr->name ) {
1721                        newBuf->attributes.push_back( attr );
1722                        return true;
1723                }
1724                return false;
1725        };
1726
1727        auto mutDecl = mutate( decl );
1728
1729        // Forally, side effects are not safe in this function. But it works.
1730        erase_if( mutDecl->attributes, matchAndMove );
1731
1732        mutDecl->init = new ast::SingleInit( decl->location,
1733                new ast::VariableExpr( decl->location, newBuf ) );
1734
1735        return ast::mutate_field( stmt, &ast::DeclStmt::decl, mutDecl );
1736}
1737
1738/// Checks if memberDecl matches the decl from an aggregate.
1739bool isMember( ast::DeclWithType const * memberDecl, ast::Decl const * decl ) {
1740        // No matter the field, if the name is different it is not the same.
1741        if ( memberDecl->name != decl->name ) {
1742                return false;
1743        }
1744
1745        if ( memberDecl->name.empty() ) {
1746                // Plan-9 Field: Match on unique_id.
1747                return ( memberDecl->uniqueId == decl->uniqueId );
1748        }
1749
1750        ast::DeclWithType const * declWithType =
1751                strict_dynamic_cast<ast::DeclWithType const *>( decl );
1752
1753        if ( memberDecl->mangleName.empty() || declWithType->mangleName.empty() ) {
1754                // Tuple-Element Field: Expect neither had mangled name;
1755                // accept match on simple name (like field_2) only.
1756                assert( memberDecl->mangleName.empty() );
1757                assert( declWithType->mangleName.empty() );
1758                return true;
1759        }
1760
1761        // Ordinary Field: Use full name to accommodate overloading.
1762        return ( memberDecl->mangleName == declWithType->mangleName );
1763}
1764
1765/// Finds the member in the base list that matches the given declaration;
1766/// returns its index, or -1 if not present.
1767long findMember( ast::DeclWithType const * memberDecl,
1768                const ast::vector<ast::Decl> & baseDecls ) {
1769        for ( auto pair : enumerate( baseDecls ) ) {
1770                if ( isMember( memberDecl, pair.val.get() ) ) {
1771                        return pair.idx;
1772                }
1773        }
1774        return -1;
1775}
1776
1777/// Returns an index expression into the offset array for a type.
1778ast::Expr * makeOffsetIndex( CodeLocation const & location,
1779                ast::Type const * objectType, long i ) {
1780        std::string name = offsetofName( Mangle::mangleType( objectType ) );
1781        return ast::UntypedExpr::createCall( location, "?[?]", {
1782                new ast::NameExpr( location, name ),
1783                ast::ConstantExpr::from_ulong( location, i ),
1784        } );
1785}
1786
1787ast::Expr const * PolyGenericCalculator::postvisit(
1788                ast::MemberExpr const * expr ) {
1789        // Only mutate member expressions for polymorphic types.
1790        ast::Type const * objectType = hasPolyBase(
1791                expr->aggregate->result, scopeTypeVars
1792        );
1793        if ( !objectType ) return expr;
1794        // Ensure layout for this type is available.
1795        // The boolean result is ignored.
1796        findGeneric( expr->location, objectType );
1797
1798        // Replace member expression with dynamically-computed layout expression.
1799        ast::Expr * newMemberExpr = nullptr;
1800        if ( auto structType = dynamic_cast<ast::StructInstType const *>( objectType ) ) {
1801                long offsetIndex = findMember( expr->member, structType->base->members );
1802                if ( -1 == offsetIndex ) return expr;
1803
1804                // Replace member expression with pointer to struct plus offset.
1805                ast::UntypedExpr * fieldLoc = new ast::UntypedExpr( expr->location,
1806                                new ast::NameExpr( expr->location, "?+?" ) );
1807                ast::Expr * aggr = deepCopy( expr->aggregate );
1808                aggr->env = nullptr;
1809                fieldLoc->args.push_back( aggr );
1810                fieldLoc->args.push_back(
1811                        makeOffsetIndex( expr->location, objectType, offsetIndex ) );
1812                fieldLoc->result = deepCopy( expr->result );
1813                newMemberExpr = fieldLoc;
1814        // Union members are all at offset zero, so just use the aggregate expr.
1815        } else if ( dynamic_cast<ast::UnionInstType const *>( objectType ) ) {
1816                ast::Expr * aggr = deepCopy( expr->aggregate );
1817                aggr->env = nullptr;
1818                aggr->result = deepCopy( expr->result );
1819                newMemberExpr = aggr;
1820        } else {
1821                return expr;
1822        }
1823        assert( newMemberExpr );
1824
1825        // Must apply the generic substitution to the member type to handle cases
1826        // where the member is a generic parameter subsituted by a known concrete
1827        // type. [ex]
1828        //      forall( T ) struct Box { T x; }
1829        //      forall( T ) void f() {
1830        //              Box( T * ) b; b.x;
1831        //      }
1832        // TODO: expr->result should be exactly expr->member->get_type() after
1833        // substitution, so it doesn't seem like it should be necessary to apply
1834        // the substitution manually. For some reason this is not currently the
1835        // case. This requires more investigation.
1836        ast::ptr<ast::Type> memberType = deepCopy( expr->member->get_type() );
1837        ast::TypeSubstitution sub = genericSubstitution( objectType );
1838        sub.apply( memberType );
1839
1840        // Not all members of a polymorphic type are themselves of a polymorphic
1841        // type; in this cas the member expression should be wrapped and
1842        // dereferenced to form an lvalue.
1843        if ( !isPolyType( memberType, scopeTypeVars ) ) {
1844                auto ptrCastExpr = new ast::CastExpr( expr->location, newMemberExpr,
1845                        new ast::PointerType( memberType ) );
1846                auto derefExpr = ast::UntypedExpr::createDeref( expr->location,
1847                        ptrCastExpr );
1848                newMemberExpr = derefExpr;
1849        }
1850
1851        return newMemberExpr;
1852}
1853
1854void PolyGenericCalculator::previsit( ast::AddressExpr const * expr ) {
1855        GuardValue( addrMember ) = expr->arg.as<ast::MemberExpr>();
1856}
1857
1858ast::Expr const * PolyGenericCalculator::postvisit(
1859                ast::AddressExpr const * expr ) {
1860        // arg has to have been a MemberExpr and has been mutated.
1861        if ( nullptr == addrMember || expr->arg == addrMember ) {
1862                return expr;
1863        }
1864        ast::UntypedExpr const * untyped = expr->arg.as<ast::UntypedExpr>();
1865        if ( !untyped || getFunctionName( untyped ) != "?+?" ) {
1866                return expr;
1867        }
1868        // MemberExpr was converted to pointer + offset; and it is not valid C to
1869        // take the address of an addition, so strip away the address-of.
1870        // It also preserves the env value.
1871        return ast::mutate_field( expr->arg.get(), &ast::Expr::env, expr->env );
1872}
1873
1874ast::Expr const * PolyGenericCalculator::postvisit(
1875                ast::SizeofExpr const * expr ) {
1876        ast::Type const * type = expr->type ? expr->type : expr->expr->result;
1877        ast::Expr const * gen = genSizeof( expr->location, type );
1878        return ( gen ) ? gen : expr;
1879}
1880
1881ast::Expr const * PolyGenericCalculator::postvisit(
1882                ast::AlignofExpr const * expr ) {
1883        ast::Type const * type = expr->type ? expr->type : expr->expr->result;
1884        if ( findGeneric( expr->location, type ) ) {
1885                return new ast::NameExpr( expr->location,
1886                        alignofName( Mangle::mangleType( type ) ) );
1887        } else {
1888                return expr;
1889        }
1890}
1891
1892ast::Expr const * PolyGenericCalculator::postvisit(
1893                ast::OffsetofExpr const * expr ) {
1894        ast::Type const * type = expr->type;
1895        if ( !findGeneric( expr->location, type ) ) return expr;
1896
1897        // Structures replace offsetof expression with an index into offset array.
1898        if ( auto structType = dynamic_cast<ast::StructInstType const *>( type ) ) {
1899                long offsetIndex = findMember( expr->member, structType->base->members );
1900                if ( -1 == offsetIndex ) return expr;
1901
1902                return makeOffsetIndex( expr->location, type, offsetIndex );
1903        // All union members are at offset zero.
1904        } else if ( dynamic_cast<ast::UnionInstType const *>( type ) ) {
1905                return ast::ConstantExpr::from_ulong( expr->location, 0 );
1906        } else {
1907                return expr;
1908        }
1909}
1910
1911ast::Expr const * PolyGenericCalculator::postvisit(
1912                ast::OffsetPackExpr const * expr ) {
1913        ast::StructInstType const * type = expr->type;
1914
1915        // Pull offset back from generated type information.
1916        if ( findGeneric( expr->location, type ) ) {
1917                return new ast::NameExpr( expr->location,
1918                        offsetofName( Mangle::mangleType( type ) ) );
1919        }
1920
1921        std::string offsetName = offsetofName( Mangle::mangleType( type ) );
1922        // Use the already generated offsets for this type.
1923        if ( knownOffsets.contains( offsetName ) ) {
1924                return new ast::NameExpr( expr->location, offsetName );
1925        }
1926
1927        knownOffsets.insert( offsetName );
1928
1929        // Build initializer list for offset array.
1930        ast::vector<ast::Init> inits;
1931        for ( ast::ptr<ast::Decl> const & member : type->base->members ) {
1932                auto memberDecl = member.as<ast::DeclWithType>();
1933                assertf( memberDecl, "Requesting offset of non-DWT member: %s",
1934                        toCString( member ) );
1935                inits.push_back( new ast::SingleInit( expr->location,
1936                        new ast::OffsetofExpr( expr->location,
1937                                deepCopy( type ),
1938                                memberDecl
1939                        )
1940                ) );
1941        }
1942
1943        auto offsetArray = makeVar( expr->location, offsetName,
1944                new ast::ArrayType(
1945                        makeLayoutType(),
1946                        ast::ConstantExpr::from_ulong( expr->location, inits.size() ),
1947                        ast::FixedLen,
1948                        ast::DynamicDim
1949                ),
1950                new ast::ListInit( expr->location, std::move( inits ) )
1951        );
1952
1953        return new ast::VariableExpr( expr->location, offsetArray );
1954}
1955
1956void PolyGenericCalculator::beginScope() {
1957        knownLayouts.beginScope();
1958        knownOffsets.beginScope();
1959}
1960
1961void PolyGenericCalculator::endScope() {
1962        knownOffsets.endScope();
1963        knownLayouts.endScope();
1964}
1965
1966ast::ObjectDecl * PolyGenericCalculator::makeVar(
1967                CodeLocation const & location, std::string const & name,
1968                ast::Type const * type, ast::Init const * init ) {
1969        ast::ObjectDecl * ret = new ast::ObjectDecl( location, name, type, init );
1970        stmtsToAddBefore.push_back( new ast::DeclStmt( location, ret ) );
1971        return ret;
1972}
1973
1974/// Returns true if any of the otype parameters have a dynamic layout; and
1975/// puts all otype parameters in the output list.
1976bool findGenericParams(
1977                ast::vector<ast::Type> & out,
1978                ast::vector<ast::TypeDecl> const & baseParams,
1979                ast::vector<ast::Expr> const & typeParams ) {
1980        bool hasDynamicLayout = false;
1981
1982        for ( auto pair : group_iterate( baseParams, typeParams ) ) {
1983                auto baseParam = std::get<0>( pair );
1984                auto typeParam = std::get<1>( pair );
1985                if ( !baseParam->isComplete() ) continue;
1986                ast::TypeExpr const * typeExpr = typeParam.as<ast::TypeExpr>();
1987                assertf( typeExpr, "All type parameters should be type expressions." );
1988
1989                ast::Type const * type = typeExpr->type.get();
1990                out.push_back( type );
1991                if ( isPolyType( type ) ) hasDynamicLayout = true;
1992        }
1993
1994        return hasDynamicLayout;
1995}
1996
1997bool PolyGenericCalculator::findGeneric(
1998                CodeLocation const & location, ast::Type const * type ) {
1999        type = replaceTypeInst( type, typeSubs );
2000
2001        if ( auto inst = dynamic_cast<ast::TypeInstType const *>( type ) ) {
2002                // Assumes that getting put in the scopeTypeVars includes having the
2003                // layout variables set.
2004                if ( scopeTypeVars.contains( *inst ) ) {
2005                        return true;
2006                }
2007        } else if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) {
2008                // Check if this type already has a layout generated for it.
2009                std::string typeName = Mangle::mangleType( type );
2010                if ( knownLayouts.contains( typeName ) ) return true;
2011
2012                // Check if any type parameters have dynamic layout;
2013                // If none do, this type is (or will be) monomorphized.
2014                ast::vector<ast::Type> sizedParams;
2015                if ( !findGenericParams( sizedParams,
2016                                inst->base->params, inst->params ) ) {
2017                        return false;
2018                }
2019
2020                // Insert local variables for layout and generate call to layout
2021                // function.
2022                // Done early so as not to interfere with the later addition of
2023                // parameters to the layout call.
2024                knownLayouts.insert( typeName );
2025
2026                int memberCount = inst->base->members.size();
2027                if ( 0 == memberCount ) {
2028                        // All empty structures have the same layout (size 1, align 1).
2029                        makeVar( location,
2030                                sizeofName( typeName ), makeLayoutType(),
2031                                new ast::SingleInit( location,
2032                                                ast::ConstantExpr::from_ulong( location, 1 ) ) );
2033                        makeVar( location,
2034                                alignofName( typeName ), makeLayoutType(),
2035                                new ast::SingleInit( location,
2036                                                ast::ConstantExpr::from_ulong( location, 1 ) ) );
2037                        // Since 0-length arrays are forbidden in C, skip the offset array.
2038                } else {
2039                        ast::ObjectDecl const * sizeofVar = makeVar( location,
2040                                sizeofName( typeName ), makeLayoutType(), nullptr );
2041                        ast::ObjectDecl const * alignofVar = makeVar( location,
2042                                alignofName( typeName ), makeLayoutType(), nullptr );
2043                        ast::ObjectDecl const * offsetofVar = makeVar( location,
2044                                offsetofName( typeName ),
2045                                new ast::ArrayType(
2046                                        makeLayoutType(),
2047                                        ast::ConstantExpr::from_int( location, memberCount ),
2048                                        ast::FixedLen,
2049                                        ast::DynamicDim
2050                                ),
2051                                nullptr
2052                        );
2053
2054                        // Generate call to layout function.
2055                        ast::UntypedExpr * layoutCall = new ast::UntypedExpr( location,
2056                                new ast::NameExpr( location, layoutofName( inst->base ) ),
2057                                {
2058                                        new ast::AddressExpr(
2059                                                new ast::VariableExpr( location, sizeofVar ) ),
2060                                        new ast::AddressExpr(
2061                                                new ast::VariableExpr( location, alignofVar ) ),
2062                                        new ast::VariableExpr( location, offsetofVar ),
2063                                } );
2064
2065                        addSTypeParamsToLayoutCall( layoutCall, sizedParams );
2066
2067                        stmtsToAddBefore.emplace_back(
2068                                new ast::ExprStmt( location, layoutCall ) );
2069                }
2070
2071                return true;
2072        } else if ( auto inst = dynamic_cast<ast::UnionInstType const *>( type ) ) {
2073                // Check if this type already has a layout generated for it.
2074                std::string typeName = Mangle::mangleType( type );
2075                if ( knownLayouts.contains( typeName ) ) return true;
2076
2077                // Check if any type parameters have dynamic layout;
2078                // If none do, this type is (or will be) monomorphized.
2079                ast::vector<ast::Type> sizedParams;
2080                if ( !findGenericParams( sizedParams,
2081                                inst->base->params, inst->params ) ) {
2082                        return false;
2083                }
2084
2085                // Insert local variables for layout and generate call to layout
2086                // function.
2087                // Done early so as not to interfere with the later addition of
2088                // parameters to the layout call.
2089                knownLayouts.insert( typeName );
2090
2091                ast::ObjectDecl * sizeofVar = makeVar( location,
2092                        sizeofName( typeName ), makeLayoutType() );
2093                ast::ObjectDecl * alignofVar = makeVar( location,
2094                        alignofName( typeName ), makeLayoutType() );
2095
2096                ast::UntypedExpr * layoutCall = new ast::UntypedExpr( location,
2097                        new ast::NameExpr( location, layoutofName( inst->base ) ),
2098                        {
2099                                new ast::AddressExpr(
2100                                        new ast::VariableExpr( location, sizeofVar ) ),
2101                                new ast::AddressExpr(
2102                                        new ast::VariableExpr( location, alignofVar ) ),
2103                        } );
2104
2105                addSTypeParamsToLayoutCall( layoutCall, sizedParams );
2106
2107                stmtsToAddBefore.emplace_back(
2108                        new ast::ExprStmt( location, layoutCall ) );
2109
2110                return true;
2111        }
2112        return false;
2113}
2114
2115void PolyGenericCalculator::addSTypeParamsToLayoutCall(
2116                ast::UntypedExpr * layoutCall,
2117                const ast::vector<ast::Type> & otypeParams ) {
2118        CodeLocation const & location = layoutCall->location;
2119        ast::vector<ast::Expr> & args = layoutCall->args;
2120        for ( ast::ptr<ast::Type> const & param : otypeParams ) {
2121                if ( findGeneric( location, param ) ) {
2122                        // Push size/align vars for a generic parameter back.
2123                        std::string paramName = Mangle::mangleType( param );
2124                        args.emplace_back(
2125                                new ast::NameExpr( location, sizeofName( paramName ) ) );
2126                        args.emplace_back(
2127                                new ast::NameExpr( location, alignofName( paramName ) ) );
2128                } else {
2129                        args.emplace_back(
2130                                new ast::SizeofExpr( location, ast::deepCopy( param ) ) );
2131                        args.emplace_back(
2132                                new ast::AlignofExpr( location, ast::deepCopy( param ) ) );
2133                }
2134        }
2135}
2136
2137void PolyGenericCalculator::mutateMembers( ast::AggregateDecl * aggr ) {
2138        std::set<std::string> genericParams;
2139        for ( ast::ptr<ast::TypeDecl> const & decl : aggr->params ) {
2140                genericParams.insert( decl->name );
2141        }
2142        for ( ast::ptr<ast::Decl> & decl : aggr->members ) {
2143                auto field = decl.as<ast::ObjectDecl>();
2144                if ( nullptr == field ) continue;
2145
2146                ast::Type const * type = replaceTypeInst( field->type, typeSubs );
2147                auto typeInst = dynamic_cast<ast::TypeInstType const *>( type );
2148                if ( nullptr == typeInst ) continue;
2149
2150                // Do not try to monoporphize generic parameters.
2151                if ( scopeTypeVars.contains( ast::TypeEnvKey( *typeInst ) ) &&
2152                                !genericParams.count( typeInst->name ) ) {
2153                        // Polymorphic aggregate members should be converted into
2154                        // monomorphic members. Using char[size_T] here respects
2155                        // the expected sizing rules of an aggregate type.
2156                        decl = ast::mutate_field( field, &ast::ObjectDecl::type,
2157                                polyToMonoType( field->location, field->type ) );
2158                }
2159        }
2160}
2161
2162ast::Expr const * PolyGenericCalculator::genSizeof(
2163                CodeLocation const & location, ast::Type const * type ) {
2164        if ( auto * array = dynamic_cast<ast::ArrayType const *>( type ) ) {
2165                // Generate calculated size for possibly generic array.
2166                ast::Expr const * sizeofBase = genSizeof( location, array->base );
2167                if ( nullptr == sizeofBase ) return nullptr;
2168                ast::Expr const * dim = array->dimension;
2169                return makeOp( location, "?*?", sizeofBase, dim );
2170        } else if ( findGeneric( location, type ) ) {
2171                // Generate calculated size for generic type.
2172                return new ast::NameExpr( location, sizeofName(
2173                                Mangle::mangleType( type ) ) );
2174        } else {
2175                return nullptr;
2176        }
2177}
2178
2179void PolyGenericCalculator::beginTypeScope( ast::Type const * type ) {
2180        GuardScope( scopeTypeVars );
2181        makeTypeVarMap( type, scopeTypeVars );
2182}
2183
2184// --------------------------------------------------------------------------
2185/// Removes unneeded or incorrect type information.
2186/// * Replaces initialization of polymorphic values with alloca.
2187/// * Replaces declaration of dtype/ftype with appropriate void expression.
2188/// * Replaces sizeof expressions of polymorphic types with a variable.
2189/// * Strips fields from generic structure declarations.
2190struct Eraser final :
2191                public ast::WithGuards {
2192        void guardTypeVarMap( ast::Type const * type ) {
2193                GuardScope( scopeTypeVars );
2194                makeTypeVarMap( type, scopeTypeVars );
2195        }
2196
2197        ast::ObjectDecl const * previsit( ast::ObjectDecl const * decl );
2198        ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl );
2199        ast::FunctionDecl const * postvisit( ast::FunctionDecl const * decl );
2200        ast::TypedefDecl const * previsit( ast::TypedefDecl const * decl );
2201        ast::StructDecl const * previsit( ast::StructDecl const * decl );
2202        ast::UnionDecl const * previsit( ast::UnionDecl const * decl );
2203        void previsit( ast::TypeDecl const * decl );
2204        void previsit( ast::PointerType const * type );
2205        void previsit( ast::FunctionType const * type );
2206public:
2207        TypeVarMap scopeTypeVars;
2208};
2209
2210ast::ObjectDecl const * Eraser::previsit( ast::ObjectDecl const * decl ) {
2211        guardTypeVarMap( decl->type );
2212        return scrubAllTypeVars( decl );
2213}
2214
2215ast::FunctionDecl const * Eraser::previsit( ast::FunctionDecl const * decl ) {
2216        guardTypeVarMap( decl->type );
2217        return scrubAllTypeVars( decl );
2218}
2219
2220ast::FunctionDecl const * Eraser::postvisit( ast::FunctionDecl const * decl ) {
2221        if ( decl->type_params.empty() ) return decl;
2222        auto mutDecl = mutate( decl );
2223        mutDecl->type_params.clear();
2224        return mutDecl;
2225}
2226
2227ast::TypedefDecl const * Eraser::previsit( ast::TypedefDecl const * decl ) {
2228        guardTypeVarMap( decl->base );
2229        return scrubAllTypeVars( decl );
2230}
2231
2232/// Strips the members from a generic aggregate.
2233template<typename node_t>
2234node_t const * stripGenericMembers( node_t const * decl ) {
2235        if ( decl->params.empty() ) return decl;
2236        auto mutDecl = ast::mutate( decl );
2237        mutDecl->members.clear();
2238        return mutDecl;
2239}
2240
2241ast::StructDecl const * Eraser::previsit( ast::StructDecl const * decl ) {
2242        return stripGenericMembers( decl );
2243}
2244
2245ast::UnionDecl const * Eraser::previsit( ast::UnionDecl const * decl ) {
2246        return stripGenericMembers( decl );
2247}
2248
2249void Eraser::previsit( ast::TypeDecl const * decl ) {
2250        addToTypeVarMap( decl, scopeTypeVars );
2251}
2252
2253void Eraser::previsit( ast::PointerType const * type ) {
2254        guardTypeVarMap( type );
2255}
2256
2257void Eraser::previsit( ast::FunctionType const * type ) {
2258        guardTypeVarMap( type );
2259}
2260
2261} // namespace
2262
2263// --------------------------------------------------------------------------
2264void box( ast::TranslationUnit & translationUnit ) {
2265        ast::Pass<LayoutFunctionBuilder>::run( translationUnit );
2266        ast::Pass<CallAdapter>::run( translationUnit );
2267        ast::Pass<DeclAdapter>::run( translationUnit );
2268        ast::Pass<RewireAdapters>::run( translationUnit );
2269        ast::Pass<PolyGenericCalculator>::run( translationUnit );
2270        ast::Pass<Eraser>::run( translationUnit );
2271}
2272
2273} // namespace GenPoly
2274
2275// Local Variables: //
2276// tab-width: 4 //
2277// mode: c++ //
2278// compile-command: "make install" //
2279// End: //
Note: See TracBrowser for help on using the repository browser.