source: src/GenPoly/BoxNew.cpp @ 37ceccb

Last change on this file since 37ceccb was 52a5262e, checked in by Andrew Beach <ajbeach@…>, 9 months ago

TypeVarMap? is now a subtype instead of an alias to remove the redundent constructor argument. Various bits of box pass clean-up.

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