source: src/ResolvExpr/Resolver.cc @ 221c542e

Last change on this file since 221c542e was 59c8dff, checked in by JiadaL <j82liang@…>, 7 months ago

Draft Implementation for enum position pesudo function (posE). EnumPosExpr? is mostly irrelevant for now. It is used in development/code probing and will be removed later

  • Property mode set to 100644
File size: 45.0 KB
RevLine 
[a32b204]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//
[71f4e4f]7// Resolver.cc --
[a32b204]8//
[d76c588]9// Author           : Aaron B. Moss
[a32b204]10// Created On       : Sun May 17 12:17:01 2015
[4c2fe47]11// Last Modified By : Peter A. Buhr
[ca9d65e]12// Last Modified On : Thu Dec 14 18:44:43 2023
13// Update Count     : 251
[a32b204]14//
15
[e3e16bc]16#include <cassert>                       // for strict_dynamic_cast, assert
[ea6332d]17#include <memory>                        // for allocator, allocator_traits<...
18#include <tuple>                         // for get
[6d6e829]19#include <vector>                        // for vector
[ea6332d]20
[99d4584]21#include "Candidate.hpp"
22#include "CandidateFinder.hpp"
[d76c588]23#include "CurrentObject.h"               // for CurrentObject
24#include "RenameVars.h"                  // for RenameVars, global_renamer
25#include "Resolver.h"
[16ba4a6]26#include "ResolveTypeof.h"
[4a89b52]27#include "ResolveMode.hpp"               // for ResolveMode
[d76c588]28#include "typeops.h"                     // for extractResultType
29#include "Unify.h"                       // for unify
[16ba4a6]30#include "CompilationState.h"
[2a8f0c1]31#include "AST/Decl.hpp"
32#include "AST/Init.hpp"
[d76c588]33#include "AST/Pass.hpp"
[99d4584]34#include "AST/Print.hpp"
[d76c588]35#include "AST/SymbolTable.hpp"
[2773ab8]36#include "AST/Type.hpp"
[8f06277]37#include "Common/Eval.h"                 // for eval
[9feb34b]38#include "Common/Iterate.hpp"            // for group_iterate
[ea6332d]39#include "Common/SemanticError.h"        // for SemanticError
[57e0289]40#include "Common/Stats/ResolveTime.h"    // for ResolveTime::start(), ResolveTime::stop()
[9feb34b]41#include "Common/ToString.hpp"           // for toCString
[c6b4432]42#include "Common/UniqueName.h"           // for UniqueName
[0a60c04]43#include "InitTweak/GenInit.h"
[ea6332d]44#include "InitTweak/InitTweak.h"         // for isIntrinsicSingleArgCallStmt
[16ba4a6]45#include "SymTab/Mangler.h"              // for Mangler
[0a60c04]46#include "Tuples/Tuples.h"
[2bfc6b2]47#include "Validate/FindSpecialDecls.h"   // for SizeType
[51b7345]48
[d9a0e76]49using namespace std;
[51b7345]50
[d9a0e76]51namespace ResolvExpr {
[1dcd9554]52        template< typename iterator_t >
53        inline bool advance_to_mutex( iterator_t & it, const iterator_t & end ) {
54                while( it != end && !(*it)->get_type()->get_mutex() ) {
55                        it++;
56                }
57
58                return it != end;
59        }
60
[99d4584]61        namespace {
62                /// Finds deleted expressions in an expression tree
[0bd3faf]63                struct DeleteFinder final : public ast::WithShortCircuiting, public ast::WithVisitorRef<DeleteFinder> {
[e6b42e7]64                        const ast::DeletedExpr * result = nullptr;
[99d4584]65
66                        void previsit( const ast::DeletedExpr * expr ) {
[e6b42e7]67                                if ( result ) { visit_children = false; }
68                                else { result = expr; }
[99d4584]69                        }
70
[361bf01]71                        void previsit( const ast::Expr * expr ) {
[e6b42e7]72                                if ( result ) { visit_children = false; }
[361bf01]73                                if (expr->inferred.hasParams()) {
74                                        for (auto & imp : expr->inferred.inferParams() ) {
[2dda05d]75                                                imp.second.expr->accept(*visitor);
[361bf01]76                                        }
77                                }
[99d4584]78                        }
79                };
[4894239]80
[0bd3faf]81                struct ResolveDesignators final : public ast::WithShortCircuiting {
[4894239]82                        ResolveContext& context;
83                        bool result = false;
84
[0bd3faf]85                        ResolveDesignators( ResolveContext& _context ): context{_context} {};
[4894239]86
87                        void previsit( const ast::Node * ) {
88                                // short circuit if we already know there are designations
89                                if ( result ) visit_children = false;
90                        }
91
92                        void previsit( const ast::Designation * des ) {
93                                if ( result ) visit_children = false;
94                                else if ( ! des->designators.empty() ) {
95                                        if ( (des->designators.size() == 1) ) {
96                                                const ast::Expr * designator = des->designators.at(0);
97                                                if ( const ast::NameExpr * designatorName = dynamic_cast<const ast::NameExpr *>(designator) ) {
98                                                        auto candidates = context.symtab.lookupId(designatorName->name);
99                                                        for ( auto candidate : candidates ) {
100                                                                if ( dynamic_cast<const ast::EnumInstType *>(candidate.id->get_type()) ) {
101                                                                        result = true;
102                                                                        break;
103                                                                }
104                                                        }
[2345ab3]105                                                }
106                                        }
[4894239]107                                        visit_children = false;
108                                }
109                        }
110                };
[d57e349]111        } // anonymous namespace
112        /// Check if this expression is or includes a deleted expression
113        const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ) {
[0bd3faf]114                return ast::Pass<DeleteFinder>::read( expr );
[d57e349]115        }
[99d4584]116
[d57e349]117        namespace {
[b7d92b96]118                /// always-accept candidate filter
119                bool anyCandidate( const Candidate & ) { return true; }
120
[99d4584]121                /// Calls the CandidateFinder and finds the single best candidate
122                CandidateRef findUnfinishedKindExpression(
[39d8950]123                        const ast::Expr * untyped, const ResolveContext & context, const std::string & kind,
[4a89b52]124                        std::function<bool(const Candidate &)> pred = anyCandidate, ResolveMode mode = {}
[99d4584]125                ) {
126                        if ( ! untyped ) return nullptr;
127
128                        // xxx - this isn't thread-safe, but should work until we parallelize the resolver
129                        static unsigned recursion_level = 0;
130
131                        ++recursion_level;
132                        ast::TypeEnvironment env;
[39d8950]133                        CandidateFinder finder( context, env );
[46da46b]134                        finder.allowVoid = true;
[99d4584]135                        finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode );
136                        --recursion_level;
137
138                        // produce a filtered list of candidates
139                        CandidateList candidates;
140                        for ( auto & cand : finder.candidates ) {
141                                if ( pred( *cand ) ) { candidates.emplace_back( cand ); }
142                        }
143
144                        // produce invalid error if no candidates
145                        if ( candidates.empty() ) {
[ef5b828]146                                SemanticError( untyped,
147                                        toString( "No reasonable alternatives for ", kind, (kind != "" ? " " : ""),
[99d4584]148                                        "expression: ") );
149                        }
150
151                        // search for cheapest candidate
152                        CandidateList winners;
153                        bool seen_undeleted = false;
154                        for ( CandidateRef & cand : candidates ) {
155                                int c = winners.empty() ? -1 : cand->cost.compare( winners.front()->cost );
156
157                                if ( c > 0 ) continue;  // skip more expensive than winner
158
159                                if ( c < 0 ) {
160                                        // reset on new cheapest
161                                        seen_undeleted = ! findDeletedExpr( cand->expr );
162                                        winners.clear();
163                                } else /* if ( c == 0 ) */ {
164                                        if ( findDeletedExpr( cand->expr ) ) {
165                                                // skip deleted expression if already seen one equivalent-cost not
166                                                if ( seen_undeleted ) continue;
167                                        } else if ( ! seen_undeleted ) {
168                                                // replace list of equivalent-cost deleted expressions with one non-deleted
169                                                winners.clear();
170                                                seen_undeleted = true;
171                                        }
172                                }
173
174                                winners.emplace_back( std::move( cand ) );
175                        }
176
177                        // promote candidate.cvtCost to .cost
[46da46b]178                        // promoteCvtCost( winners );
[99d4584]179
180                        // produce ambiguous errors, if applicable
181                        if ( winners.size() != 1 ) {
182                                std::ostringstream stream;
[ef5b828]183                                stream << "Cannot choose between " << winners.size() << " alternatives for "
[99d4584]184                                        << kind << (kind != "" ? " " : "") << "expression\n";
185                                ast::print( stream, untyped );
186                                stream << " Alternatives are:\n";
187                                print( stream, winners, 1 );
188                                SemanticError( untyped->location, stream.str() );
189                        }
190
191                        // single selected choice
192                        CandidateRef & choice = winners.front();
193
194                        // fail on only expression deleted
195                        if ( ! seen_undeleted ) {
196                                SemanticError( untyped->location, choice->expr.get(), "Unique best alternative "
197                                "includes deleted identifier in " );
198                        }
199
200                        return std::move( choice );
201                }
202
203                /// Strips extraneous casts out of an expression
[0bd3faf]204                struct StripCasts final {
[c408483]205                        const ast::Expr * postvisit( const ast::CastExpr * castExpr ) {
[ef5b828]206                                if (
[2890212]207                                        castExpr->isGenerated == ast::GeneratedCast
[ef5b828]208                                        && typesCompatible( castExpr->arg->result, castExpr->result )
[99d4584]209                                ) {
210                                        // generated cast is the same type as its argument, remove it after keeping env
[ef5b828]211                                        return ast::mutate_field(
[b7d92b96]212                                                castExpr->arg.get(), &ast::Expr::env, castExpr->env );
[99d4584]213                                }
214                                return castExpr;
215                        }
216
217                        static void strip( ast::ptr< ast::Expr > & expr ) {
[0bd3faf]218                                ast::Pass< StripCasts > stripper;
[99d4584]219                                expr = expr->accept( stripper );
220                        }
221                };
222
[60aaa51d]223                /// Swaps argument into expression pointer, saving original environment
224                void swap_and_save_env( ast::ptr< ast::Expr > & expr, const ast::Expr * newExpr ) {
225                        ast::ptr< ast::TypeSubstitution > env = expr->env;
226                        expr.set_and_mutate( newExpr )->env = env;
227                }
228
[b7d92b96]229                /// Removes cast to type of argument (unlike StripCasts, also handles non-generated casts)
[918e4165]230                void removeExtraneousCast( ast::ptr<ast::Expr> & expr ) {
[b7d92b96]231                        if ( const ast::CastExpr * castExpr = expr.as< ast::CastExpr >() ) {
[251ce80]232                                if ( typesCompatible( castExpr->arg->result, castExpr->result ) ) {
[b7d92b96]233                                        // cast is to the same type as its argument, remove it
[60aaa51d]234                                        swap_and_save_env( expr, castExpr->arg );
[b7d92b96]235                                }
236                        }
237                }
238
[6668a3e]239
[490fb92e]240        } // anonymous namespace
241/// Establish post-resolver invariants for expressions
[ef5b828]242                void finishExpr(
243                        ast::ptr< ast::Expr > & expr, const ast::TypeEnvironment & env,
[99d4584]244                        const ast::TypeSubstitution * oldenv = nullptr
245                ) {
246                        // set up new type substitution for expression
[ef5b828]247                        ast::ptr< ast::TypeSubstitution > newenv =
[99d4584]248                                 oldenv ? oldenv : new ast::TypeSubstitution{};
249                        env.writeToSubstitution( *newenv.get_and_mutate() );
250                        expr.get_and_mutate()->env = std::move( newenv );
251                        // remove unncecessary casts
[0bd3faf]252                        StripCasts::strip( expr );
[99d4584]253                }
[ef5b828]254
[4b7cce6]255        ast::ptr< ast::Expr > resolveInVoidContext(
[39d8950]256                const ast::Expr * expr, const ResolveContext & context,
257                ast::TypeEnvironment & env
[4b7cce6]258        ) {
259                assertf( expr, "expected a non-null expression" );
[ef5b828]260
[4b7cce6]261                // set up and resolve expression cast to void
[417117e]262                ast::ptr< ast::CastExpr > untyped = new ast::CastExpr{ expr };
[ef5b828]263                CandidateRef choice = findUnfinishedKindExpression(
[4a89b52]264                        untyped, context, "", anyCandidate, ResolveMode::withAdjustment() );
[ef5b828]265
[4b7cce6]266                // a cast expression has either 0 or 1 interpretations (by language rules);
267                // if 0, an exception has already been thrown, and this code will not run
268                const ast::CastExpr * castExpr = choice->expr.strict_as< ast::CastExpr >();
269                env = std::move( choice->env );
270
271                return castExpr->arg;
272        }
[b7d92b96]273
[490fb92e]274        /// Resolve `untyped` to the expression whose candidate is the best match for a `void`
[b7d92b96]275                /// context.
[ef5b828]276                ast::ptr< ast::Expr > findVoidExpression(
[39d8950]277                        const ast::Expr * untyped, const ResolveContext & context
[b7d92b96]278                ) {
279                        ast::TypeEnvironment env;
[39d8950]280                        ast::ptr< ast::Expr > newExpr = resolveInVoidContext( untyped, context, env );
[b7d92b96]281                        finishExpr( newExpr, env, untyped->env );
282                        return newExpr;
283                }
284
[490fb92e]285        namespace {
[6668a3e]286
[490fb92e]287
[ef5b828]288                /// resolve `untyped` to the expression whose candidate satisfies `pred` with the
[99d4584]289                /// lowest cost, returning the resolved version
290                ast::ptr< ast::Expr > findKindExpression(
[39d8950]291                        const ast::Expr * untyped, const ResolveContext & context,
[ef5b828]292                        std::function<bool(const Candidate &)> pred = anyCandidate,
[4a89b52]293                        const std::string & kind = "", ResolveMode mode = {}
[99d4584]294                ) {
295                        if ( ! untyped ) return {};
[ef5b828]296                        CandidateRef choice =
[39d8950]297                                findUnfinishedKindExpression( untyped, context, kind, pred, mode );
[490fb92e]298                        ResolvExpr::finishExpr( choice->expr, choice->env, untyped->env );
[99d4584]299                        return std::move( choice->expr );
300                }
301
[2773ab8]302                /// Resolve `untyped` to the single expression whose candidate is the best match
[ef5b828]303                ast::ptr< ast::Expr > findSingleExpression(
[39d8950]304                        const ast::Expr * untyped, const ResolveContext & context
[2773ab8]305                ) {
[57e0289]306                        Stats::ResolveTime::start( untyped );
[39d8950]307                        auto res = findKindExpression( untyped, context );
[57e0289]308                        Stats::ResolveTime::stop();
309                        return res;
[2773ab8]310                }
[18e683b]311        } // anonymous namespace
[2773ab8]312
[16ba4a6]313        ast::ptr< ast::Expr > findSingleExpression(
[39d8950]314                const ast::Expr * untyped, const ast::Type * type,
315                const ResolveContext & context
[16ba4a6]316        ) {
317                assert( untyped && type );
318                ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped, type };
[39d8950]319                ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, context );
[918e4165]320                removeExtraneousCast( newExpr );
[16ba4a6]321                return newExpr;
322        }
[b7d92b96]323
[18e683b]324        namespace {
[16ba4a6]325                bool structOrUnion( const Candidate & i ) {
326                        const ast::Type * t = i.expr->result->stripReferences();
327                        return dynamic_cast< const ast::StructInstType * >( t ) || dynamic_cast< const ast::UnionInstType * >( t );
328                }
[99d4584]329                /// Predicate for "Candidate has integral type"
330                bool hasIntegralType( const Candidate & i ) {
331                        const ast::Type * type = i.expr->result;
[ef5b828]332
[99d4584]333                        if ( auto bt = dynamic_cast< const ast::BasicType * >( type ) ) {
334                                return bt->isInteger();
[ef5b828]335                        } else if (
336                                dynamic_cast< const ast::EnumInstType * >( type )
[99d4584]337                                || dynamic_cast< const ast::ZeroType * >( type )
338                                || dynamic_cast< const ast::OneType * >( type )
339                        ) {
340                                return true;
341                        } else return false;
342                }
343
344                /// Resolve `untyped` as an integral expression, returning the resolved version
[ef5b828]345                ast::ptr< ast::Expr > findIntegralExpression(
[39d8950]346                        const ast::Expr * untyped, const ResolveContext & context
[99d4584]347                ) {
[39d8950]348                        return findKindExpression( untyped, context, hasIntegralType, "condition" );
[99d4584]349                }
[60aaa51d]350
351                /// check if a type is a character type
352                bool isCharType( const ast::Type * t ) {
353                        if ( auto bt = dynamic_cast< const ast::BasicType * >( t ) ) {
[ef5b828]354                                return bt->kind == ast::BasicType::Char
355                                        || bt->kind == ast::BasicType::SignedChar
[60aaa51d]356                                        || bt->kind == ast::BasicType::UnsignedChar;
357                        }
358                        return false;
359                }
[2773ab8]360
361                /// Advance a type itertor to the next mutex parameter
362                template<typename Iter>
363                inline bool nextMutex( Iter & it, const Iter & end ) {
[954c954]364                        while ( it != end && ! (*it)->is_mutex() ) { ++it; }
[2773ab8]365                        return it != end;
366                }
[99d4584]367        }
368
[0bd3faf]369        class Resolver final
[4864a73]370        : public ast::WithSymbolTable, public ast::WithGuards,
[0bd3faf]371          public ast::WithVisitorRef<Resolver>, public ast::WithShortCircuiting,
[0e42794]372          public ast::WithStmtsToAdd<> {
[4864a73]373
[2a8f0c1]374                ast::ptr< ast::Type > functionReturn = nullptr;
[2b59f55]375                ast::CurrentObject currentObject;
[16ba4a6]376                // for work previously in GenInit
[0bd3faf]377                static InitTweak::ManagedTypes managedTypes;
[3bc69f2]378                ResolveContext context;
[16ba4a6]379
[99d4584]380                bool inEnumDecl = false;
[2a8f0c1]381
[4864a73]382        public:
[c15085d]383                static size_t traceId;
[0bd3faf]384                Resolver( const ast::TranslationGlobal & global ) :
[b9fe89b]385                        ast::WithSymbolTable(ast::SymbolTable::ErrorDetection::ValidateOnAdd),
[3bc69f2]386                        context{ symtab, global } {}
[0bd3faf]387                Resolver( const ResolveContext & context ) :
[3bc69f2]388                        ast::WithSymbolTable{ context.symtab },
389                        context{ symtab, context.global } {}
[d76c588]390
[16ba4a6]391                const ast::FunctionDecl * previsit( const ast::FunctionDecl * );
[99d4584]392                const ast::FunctionDecl * postvisit( const ast::FunctionDecl * );
[16ba4a6]393                const ast::ObjectDecl * previsit( const ast::ObjectDecl * );
394                void previsit( const ast::AggregateDecl * );
395                void previsit( const ast::StructDecl * );
[99d4584]396                void previsit( const ast::EnumDecl * );
397                const ast::StaticAssertDecl * previsit( const ast::StaticAssertDecl * );
398
[0f6a7752]399                const ast::ArrayType * previsit( const ast::ArrayType * );
400                const ast::PointerType * previsit( const ast::PointerType * );
[99d4584]401
[2773ab8]402                const ast::ExprStmt *        previsit( const ast::ExprStmt * );
403                const ast::AsmExpr *         previsit( const ast::AsmExpr * );
404                const ast::AsmStmt *         previsit( const ast::AsmStmt * );
405                const ast::IfStmt *          previsit( const ast::IfStmt * );
[3bc69f2]406                const ast::WhileDoStmt *     previsit( const ast::WhileDoStmt * );
[2773ab8]407                const ast::ForStmt *         previsit( const ast::ForStmt * );
408                const ast::SwitchStmt *      previsit( const ast::SwitchStmt * );
[400b8be]409                const ast::CaseClause *      previsit( const ast::CaseClause * );
[2773ab8]410                const ast::BranchStmt *      previsit( const ast::BranchStmt * );
411                const ast::ReturnStmt *      previsit( const ast::ReturnStmt * );
412                const ast::ThrowStmt *       previsit( const ast::ThrowStmt * );
[400b8be]413                const ast::CatchClause *     previsit( const ast::CatchClause * );
414                const ast::CatchClause *     postvisit( const ast::CatchClause * );
[2773ab8]415                const ast::WaitForStmt *     previsit( const ast::WaitForStmt * );
[16ba4a6]416                const ast::WithStmt *        previsit( const ast::WithStmt * );
[99d4584]417
[2d11663]418                const ast::SingleInit *      previsit( const ast::SingleInit * );
419                const ast::ListInit *        previsit( const ast::ListInit * );
420                const ast::ConstructorInit * previsit( const ast::ConstructorInit * );
[16ba4a6]421
[59c8dff]422                const ast::EnumPosExpr *         previsit( const ast::EnumPosExpr * );
423
[16ba4a6]424                void resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd);
425
426                void beginScope() { managedTypes.beginScope(); }
427                void endScope() { managedTypes.endScope(); }
[e00c22f]428                bool on_error(ast::ptr<ast::Decl> & decl);
[d76c588]429        };
[0bd3faf]430        // size_t Resolver::traceId = Stats::Heap::new_stacktrace_id("Resolver");
[d76c588]431
[0bd3faf]432        InitTweak::ManagedTypes Resolver::managedTypes;
[16ba4a6]433
[293dc1c]434        void resolve( ast::TranslationUnit& translationUnit ) {
[0bd3faf]435                ast::Pass< Resolver >::run( translationUnit, translationUnit.global );
[d76c588]436        }
437
[ef5b828]438        ast::ptr< ast::Init > resolveCtorInit(
[39d8950]439                const ast::ConstructorInit * ctorInit, const ResolveContext & context
[234b1cb]440        ) {
441                assert( ctorInit );
[0bd3faf]442                ast::Pass< Resolver > resolver( context );
[234b1cb]443                return ctorInit->accept( resolver );
444        }
445
[302ef2a]446        const ast::Expr * resolveStmtExpr(
[39d8950]447                const ast::StmtExpr * stmtExpr, const ResolveContext & context
[17a0ede2]448        ) {
449                assert( stmtExpr );
[0bd3faf]450                ast::Pass< Resolver > resolver( context );
[302ef2a]451                auto ret = mutate(stmtExpr->accept(resolver));
452                strict_dynamic_cast< ast::StmtExpr * >( ret )->computeResult();
[17a0ede2]453                return ret;
454        }
455
[16ba4a6]456        namespace {
[39d8950]457                const ast::Attribute * handleAttribute(const CodeLocation & loc, const ast::Attribute * attr, const ResolveContext & context) {
[16ba4a6]458                        std::string name = attr->normalizedName();
459                        if (name == "constructor" || name == "destructor") {
460                                if (attr->params.size() == 1) {
461                                        auto arg = attr->params.front();
[39d8950]462                                        auto resolved = ResolvExpr::findSingleExpression( arg, new ast::BasicType( ast::BasicType::LongLongSignedInt ), context );
[16ba4a6]463                                        auto result = eval(arg);
464
465                                        auto mutAttr = mutate(attr);
466                                        mutAttr->params.front() = resolved;
[8f557161]467                                        if (! result.hasKnownValue) {
[16ba4a6]468                                                SemanticWarning(loc, Warning::GccAttributes,
469                                                        toCString( name, " priorities must be integers from 0 to 65535 inclusive: ", arg ) );
470                                        }
471                                        else {
[8f557161]472                                                auto priority = result.knownValue;
[16ba4a6]473                                                if (priority < 101) {
474                                                        SemanticWarning(loc, Warning::GccAttributes,
475                                                                toCString( name, " priorities from 0 to 100 are reserved for the implementation" ) );
476                                                } else if (priority < 201 && ! buildingLibrary()) {
477                                                        SemanticWarning(loc, Warning::GccAttributes,
478                                                                toCString( name, " priorities from 101 to 200 are reserved for the implementation" ) );
479                                                }
480                                        }
481                                        return mutAttr;
482                                } else if (attr->params.size() > 1) {
483                                        SemanticWarning(loc, Warning::GccAttributes, toCString( "too many arguments to ", name, " attribute" ) );
484                                } else {
485                                        SemanticWarning(loc, Warning::GccAttributes, toCString( "too few arguments to ", name, " attribute" ) );
486                                }
487                        }
488                        return attr;
489                }
490        }
491
[0bd3faf]492        const ast::FunctionDecl * Resolver::previsit( const ast::FunctionDecl * functionDecl ) {
[2a8f0c1]493                GuardValue( functionReturn );
[16ba4a6]494
495                assert (functionDecl->unique());
496                if (!functionDecl->has_body() && !functionDecl->withExprs.empty()) {
497                        SemanticError(functionDecl->location, functionDecl, "Function without body has with declarations");
498                }
499
500                if (!functionDecl->isTypeFixed) {
501                        auto mutDecl = mutate(functionDecl);
502                        auto mutType = mutDecl->type.get_and_mutate();
503
504                        for (auto & attr: mutDecl->attributes) {
[3bc69f2]505                                attr = handleAttribute(mutDecl->location, attr, context );
[16ba4a6]506                        }
507
[3e5dd913]508                        // handle assertions
[16ba4a6]509
510                        symtab.enterScope();
[3e5dd913]511                        mutType->forall.clear();
512                        mutType->assertions.clear();
513                        for (auto & typeParam : mutDecl->type_params) {
514                                symtab.addType(typeParam);
[b230091]515                                mutType->forall.emplace_back(new ast::TypeInstType(typeParam));
[3e5dd913]516                        }
517                        for (auto & asst : mutDecl->assertions) {
[3bc69f2]518                                asst = fixObjectType(asst.strict_as<ast::ObjectDecl>(), context);
[3e5dd913]519                                symtab.addId(asst);
520                                mutType->assertions.emplace_back(new ast::VariableExpr(functionDecl->location, asst));
[16ba4a6]521                        }
522
523                        // temporarily adds params to symbol table.
524                        // actual scoping rules for params and withexprs differ - see Pass::visit(FunctionDecl)
525
526                        std::vector<ast::ptr<ast::Type>> paramTypes;
527                        std::vector<ast::ptr<ast::Type>> returnTypes;
528
529                        for (auto & param : mutDecl->params) {
[3bc69f2]530                                param = fixObjectType(param.strict_as<ast::ObjectDecl>(), context);
[16ba4a6]531                                symtab.addId(param);
532                                paramTypes.emplace_back(param->get_type());
533                        }
534                        for (auto & ret : mutDecl->returns) {
[3bc69f2]535                                ret = fixObjectType(ret.strict_as<ast::ObjectDecl>(), context);
[16ba4a6]536                                returnTypes.emplace_back(ret->get_type());
537                        }
538                        // since function type in decl is just a view of param types, need to update that as well
539                        mutType->params = std::move(paramTypes);
540                        mutType->returns = std::move(returnTypes);
541
[3e5dd913]542                        auto renamedType = strict_dynamic_cast<const ast::FunctionType *>(renameTyVars(mutType, RenameMode::GEN_EXPR_ID));
543
[16ba4a6]544                        std::list<ast::ptr<ast::Stmt>> newStmts;
545                        resolveWithExprs (mutDecl->withExprs, newStmts);
546
547                        if (mutDecl->stmts) {
548                                auto mutStmt = mutDecl->stmts.get_and_mutate();
549                                mutStmt->kids.splice(mutStmt->kids.begin(), std::move(newStmts));
550                                mutDecl->stmts = mutStmt;
551                        }
552
553                        symtab.leaveScope();
554
[3e5dd913]555                        mutDecl->type = renamedType;
[16ba4a6]556                        mutDecl->mangleName = Mangle::mangle(mutDecl);
557                        mutDecl->isTypeFixed = true;
558                        functionDecl = mutDecl;
559                }
560                managedTypes.handleDWT(functionDecl);
561
[2a8f0c1]562                functionReturn = extractResultType( functionDecl->type );
[16ba4a6]563                return functionDecl;
[d76c588]564        }
565
[0bd3faf]566        const ast::FunctionDecl * Resolver::postvisit( const ast::FunctionDecl * functionDecl ) {
[4864a73]567                // default value expressions have an environment which shouldn't be there and trips up
[2a8f0c1]568                // later passes.
[e068c8a]569                assert( functionDecl->unique() );
570                ast::FunctionType * mutType = mutate( functionDecl->type.get() );
571
572                for ( unsigned i = 0 ; i < mutType->params.size() ; ++i ) {
573                        if ( const ast::ObjectDecl * obj = mutType->params[i].as< ast::ObjectDecl >() ) {
574                                if ( const ast::SingleInit * init = obj->init.as< ast::SingleInit >() ) {
575                                        if ( init->value->env == nullptr ) continue;
576                                        // clone initializer minus the initializer environment
577                                        auto mutParam = mutate( mutType->params[i].strict_as< ast::ObjectDecl >() );
578                                        auto mutInit = mutate( mutParam->init.strict_as< ast::SingleInit >() );
579                                        auto mutValue = mutate( mutInit->value.get() );
580
581                                        mutValue->env = nullptr;
582                                        mutInit->value = mutValue;
583                                        mutParam->init = mutInit;
584                                        mutType->params[i] = mutParam;
585
586                                        assert( ! mutType->params[i].strict_as< ast::ObjectDecl >()->init.strict_as< ast::SingleInit >()->value->env);
587                                }
588                        }
[2a8f0c1]589                }
[73973b6]590                mutate_field(functionDecl, &ast::FunctionDecl::type, mutType);
591                return functionDecl;
[d76c588]592        }
593
[0bd3faf]594        const ast::ObjectDecl * Resolver::previsit( const ast::ObjectDecl * objectDecl ) {
[ef5b828]595                // To handle initialization of routine pointers [e.g. int (*fp)(int) = foo()],
596                // class-variable `initContext` is changed multiple times because the LHS is analyzed
597                // twice. The second analysis changes `initContext` because a function type can contain
598                // object declarations in the return and parameter types. Therefore each value of
599                // `initContext` is retained so the type on the first analysis is preserved and used for
[b7d92b96]600                // selecting the RHS.
601                GuardValue( currentObject );
[16ba4a6]602
[b7d92b96]603                if ( inEnumDecl && dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() ) ) {
[ef5b828]604                        // enumerator initializers should not use the enum type to initialize, since the
[b7d92b96]605                        // enum type is still incomplete at this point. Use `int` instead.
[4559b34]606
[12df6fe]607                        if ( auto enumBase = dynamic_cast< const ast::EnumInstType * >
608                                ( objectDecl->get_type() )->base->base ) {
[5bb1ac1]609                                objectDecl = fixObjectType( objectDecl, context );
[2345ab3]610                                currentObject = ast::CurrentObject{
611                                        objectDecl->location,
[5bb1ac1]612                                        enumBase
613                                };
[4559b34]614                        } else {
[5bb1ac1]615                                objectDecl = fixObjectType( objectDecl, context );
[4559b34]616                                currentObject = ast::CurrentObject{
617                                        objectDecl->location, new ast::BasicType{ ast::BasicType::SignedInt } };
618                        }
619
[b7d92b96]620                }
[16ba4a6]621                else {
[12df6fe]622                        if ( !objectDecl->isTypeFixed ) {
[3bc69f2]623                                auto newDecl = fixObjectType(objectDecl, context);
[16ba4a6]624                                auto mutDecl = mutate(newDecl);
[4a8f150]625
[16ba4a6]626                                // generate CtorInit wrapper when necessary.
627                                // in certain cases, fixObjectType is called before reaching
628                                // this object in visitor pass, thus disabling CtorInit codegen.
629                                // this happens on aggregate members and function parameters.
630                                if ( InitTweak::tryConstruct( mutDecl ) && ( managedTypes.isManaged( mutDecl ) || ((! isInFunction() || mutDecl->storage.is_static ) && ! InitTweak::isConstExpr( mutDecl->init ) ) ) ) {
631                                        // constructed objects cannot be designated
[92355883]632                                        if ( InitTweak::isDesignated( mutDecl->init ) ) {
[0bd3faf]633                                                ast::Pass<ResolveDesignators> res( context );
[4894239]634                                                maybe_accept( mutDecl->init.get(), res );
635                                                if ( !res.core.result ) {
[ca9d65e]636                                                        SemanticError( mutDecl, "Cannot include designations in the initializer for a managed Object.\n"
637                                                                                   "If this is really what you want, initialize with @=." );
[4894239]638                                                }
[92355883]639                                        }
[16ba4a6]640                                        // constructed objects should not have initializers nested too deeply
641                                        if ( ! InitTweak::checkInitDepth( mutDecl ) ) SemanticError( mutDecl, "Managed object's initializer is too deep " );
642
643                                        mutDecl->init = InitTweak::genCtorInit( mutDecl->location, mutDecl );
644                                }
645
646                                objectDecl = mutDecl;
647                        }
648                        currentObject = ast::CurrentObject{ objectDecl->location, objectDecl->get_type() };
649                }
[4a8f150]650
[16ba4a6]651                return objectDecl;
652        }
653
[0bd3faf]654        void Resolver::previsit( const ast::AggregateDecl * _aggDecl ) {
[16ba4a6]655                auto aggDecl = mutate(_aggDecl);
656                assertf(aggDecl == _aggDecl, "type declarations must be unique");
657
658                for (auto & member: aggDecl->members) {
659                        // nested type decls are hoisted already. no need to do anything
660                        if (auto obj = member.as<ast::ObjectDecl>()) {
[3bc69f2]661                                member = fixObjectType(obj, context);
[16ba4a6]662                        }
663                }
664        }
665
[0bd3faf]666        void Resolver::previsit( const ast::StructDecl * structDecl ) {
[16ba4a6]667                previsit(static_cast<const ast::AggregateDecl *>(structDecl));
668                managedTypes.handleStruct(structDecl);
[d76c588]669        }
670
[0bd3faf]671        void Resolver::previsit( const ast::EnumDecl * ) {
[99d4584]672                // in case we decide to allow nested enums
673                GuardValue( inEnumDecl );
[2890212]674                inEnumDecl = true;
[16ba4a6]675                // don't need to fix types for enum fields
[d76c588]676        }
677
[0bd3faf]678        const ast::StaticAssertDecl * Resolver::previsit(
[ef5b828]679                const ast::StaticAssertDecl * assertDecl
[99d4584]680        ) {
[ef5b828]681                return ast::mutate_field(
682                        assertDecl, &ast::StaticAssertDecl::cond,
[3bc69f2]683                        findIntegralExpression( assertDecl->cond, context ) );
[b7d92b96]684        }
685
686        template< typename PtrType >
[39d8950]687        const PtrType * handlePtrType( const PtrType * type, const ResolveContext & context ) {
[0f6a7752]688                if ( type->dimension ) {
[5cf1228]689                        const ast::Type * sizeType = context.global.sizeType.get();
[9e23b446]690                        ast::ptr< ast::Expr > dimension = findSingleExpression( type->dimension, sizeType, context );
691                        assertf(dimension->env->empty(), "array dimension expr has nonempty env");
692                        dimension.get_and_mutate()->env = nullptr;
[5cf1228]693                        ast::mutate_field( type, &PtrType::dimension, dimension );
[0f6a7752]694                }
695                return type;
[d76c588]696        }
697
[0bd3faf]698        const ast::ArrayType * Resolver::previsit( const ast::ArrayType * at ) {
[3bc69f2]699                return handlePtrType( at, context );
[d76c588]700        }
701
[0bd3faf]702        const ast::PointerType * Resolver::previsit( const ast::PointerType * pt ) {
[3bc69f2]703                return handlePtrType( pt, context );
[d76c588]704        }
705
[0bd3faf]706        const ast::ExprStmt * Resolver::previsit( const ast::ExprStmt * exprStmt ) {
[b7d92b96]707                visit_children = false;
708                assertf( exprStmt->expr, "ExprStmt has null expression in resolver" );
[ef5b828]709
710                return ast::mutate_field(
[3bc69f2]711                        exprStmt, &ast::ExprStmt::expr, findVoidExpression( exprStmt->expr, context ) );
[d76c588]712        }
713
[0bd3faf]714        const ast::AsmExpr * Resolver::previsit( const ast::AsmExpr * asmExpr ) {
[b7d92b96]715                visit_children = false;
716
[ef5b828]717                asmExpr = ast::mutate_field(
[3bc69f2]718                        asmExpr, &ast::AsmExpr::operand, findVoidExpression( asmExpr->operand, context ) );
[ef5b828]719
[b7d92b96]720                return asmExpr;
[d76c588]721        }
722
[0bd3faf]723        const ast::AsmStmt * Resolver::previsit( const ast::AsmStmt * asmStmt ) {
[2b59f55]724                visitor->maybe_accept( asmStmt, &ast::AsmStmt::input );
725                visitor->maybe_accept( asmStmt, &ast::AsmStmt::output );
726                visit_children = false;
727                return asmStmt;
[d76c588]728        }
729
[0bd3faf]730        const ast::IfStmt * Resolver::previsit( const ast::IfStmt * ifStmt ) {
[b7d92b96]731                return ast::mutate_field(
[3bc69f2]732                        ifStmt, &ast::IfStmt::cond, findIntegralExpression( ifStmt->cond, context ) );
[d76c588]733        }
734
[0bd3faf]735        const ast::WhileDoStmt * Resolver::previsit( const ast::WhileDoStmt * whileDoStmt ) {
[ef5b828]736                return ast::mutate_field(
[3bc69f2]737                        whileDoStmt, &ast::WhileDoStmt::cond, findIntegralExpression( whileDoStmt->cond, context ) );
[d76c588]738        }
739
[0bd3faf]740        const ast::ForStmt * Resolver::previsit( const ast::ForStmt * forStmt ) {
[b7d92b96]741                if ( forStmt->cond ) {
742                        forStmt = ast::mutate_field(
[3bc69f2]743                                forStmt, &ast::ForStmt::cond, findIntegralExpression( forStmt->cond, context ) );
[b7d92b96]744                }
745
746                if ( forStmt->inc ) {
747                        forStmt = ast::mutate_field(
[3bc69f2]748                                forStmt, &ast::ForStmt::inc, findVoidExpression( forStmt->inc, context ) );
[b7d92b96]749                }
750
751                return forStmt;
[d76c588]752        }
753
[0bd3faf]754        const ast::SwitchStmt * Resolver::previsit( const ast::SwitchStmt * switchStmt ) {
[b7d92b96]755                GuardValue( currentObject );
756                switchStmt = ast::mutate_field(
[ef5b828]757                        switchStmt, &ast::SwitchStmt::cond,
[3bc69f2]758                        findIntegralExpression( switchStmt->cond, context ) );
[2b59f55]759                currentObject = ast::CurrentObject{ switchStmt->location, switchStmt->cond->result };
[b7d92b96]760                return switchStmt;
[d76c588]761        }
762
[0bd3faf]763        const ast::CaseClause * Resolver::previsit( const ast::CaseClause * caseStmt ) {
[b7d92b96]764                if ( caseStmt->cond ) {
[60aaa51d]765                        std::deque< ast::InitAlternative > initAlts = currentObject.getOptions();
[2b59f55]766                        assertf( initAlts.size() == 1, "SwitchStmt did not correctly resolve an integral "
767                                "expression." );
[ef5b828]768
769                        ast::ptr< ast::Expr > untyped =
[2b59f55]770                                new ast::CastExpr{ caseStmt->location, caseStmt->cond, initAlts.front().type };
[3bc69f2]771                        ast::ptr< ast::Expr > newExpr = findSingleExpression( untyped, context );
[ef5b828]772
773                        // case condition cannot have a cast in C, so it must be removed here, regardless of
[2b59f55]774                        // whether it would perform a conversion.
775                        if ( const ast::CastExpr * castExpr = newExpr.as< ast::CastExpr >() ) {
[60aaa51d]776                                swap_and_save_env( newExpr, castExpr->arg );
[2b59f55]777                        }
[ef5b828]778
[400b8be]779                        caseStmt = ast::mutate_field( caseStmt, &ast::CaseClause::cond, newExpr );
[b7d92b96]780                }
781                return caseStmt;
[d76c588]782        }
783
[0bd3faf]784        const ast::BranchStmt * Resolver::previsit( const ast::BranchStmt * branchStmt ) {
[b7d92b96]785                visit_children = false;
786                // must resolve the argument of a computed goto
787                if ( branchStmt->kind == ast::BranchStmt::Goto && branchStmt->computedTarget ) {
788                        // computed goto argument is void*
[2773ab8]789                        ast::ptr< ast::Type > target = new ast::PointerType{ new ast::VoidType{} };
[b7d92b96]790                        branchStmt = ast::mutate_field(
[ef5b828]791                                branchStmt, &ast::BranchStmt::computedTarget,
[3bc69f2]792                                findSingleExpression( branchStmt->computedTarget, target, context ) );
[b7d92b96]793                }
794                return branchStmt;
[d76c588]795        }
796
[0bd3faf]797        const ast::ReturnStmt * Resolver::previsit( const ast::ReturnStmt * returnStmt ) {
[2b59f55]798                visit_children = false;
799                if ( returnStmt->expr ) {
800                        returnStmt = ast::mutate_field(
[ef5b828]801                                returnStmt, &ast::ReturnStmt::expr,
[3bc69f2]802                                findSingleExpression( returnStmt->expr, functionReturn, context ) );
[2b59f55]803                }
804                return returnStmt;
[d76c588]805        }
806
[0bd3faf]807        const ast::ThrowStmt * Resolver::previsit( const ast::ThrowStmt * throwStmt ) {
[2b59f55]808                visit_children = false;
809                if ( throwStmt->expr ) {
[ef5b828]810                        const ast::StructDecl * exceptionDecl =
[3090127]811                                symtab.lookupStruct( "__cfaehm_base_exception_t" );
[2b59f55]812                        assert( exceptionDecl );
[ef5b828]813                        ast::ptr< ast::Type > exceptType =
[2b59f55]814                                new ast::PointerType{ new ast::StructInstType{ exceptionDecl } };
815                        throwStmt = ast::mutate_field(
[ef5b828]816                                throwStmt, &ast::ThrowStmt::expr,
[3bc69f2]817                                findSingleExpression( throwStmt->expr, exceptType, context ) );
[2b59f55]818                }
819                return throwStmt;
[d76c588]820        }
821
[0bd3faf]822        const ast::CatchClause * Resolver::previsit( const ast::CatchClause * catchClause ) {
[3b0bc16]823                // Until we are very sure this invarent (ifs that move between passes have then)
[b9fa85b]824                // holds, check it. This allows a check for when to decode the mangling.
[400b8be]825                if ( auto ifStmt = catchClause->body.as<ast::IfStmt>() ) {
[3b0bc16]826                        assert( ifStmt->then );
[b9fa85b]827                }
828                // Encode the catchStmt so the condition can see the declaration.
[400b8be]829                if ( catchClause->cond ) {
830                        ast::CatchClause * clause = mutate( catchClause );
831                        clause->body = new ast::IfStmt( clause->location, clause->cond, nullptr, clause->body );
832                        clause->cond = nullptr;
833                        return clause;
[b9fa85b]834                }
[400b8be]835                return catchClause;
[b9fa85b]836        }
837
[0bd3faf]838        const ast::CatchClause * Resolver::postvisit( const ast::CatchClause * catchClause ) {
[b9fa85b]839                // Decode the catchStmt so everything is stored properly.
[400b8be]840                const ast::IfStmt * ifStmt = catchClause->body.as<ast::IfStmt>();
[3b0bc16]841                if ( nullptr != ifStmt && nullptr == ifStmt->then ) {
[b9fa85b]842                        assert( ifStmt->cond );
[3b0bc16]843                        assert( ifStmt->else_ );
[400b8be]844                        ast::CatchClause * clause = ast::mutate( catchClause );
845                        clause->cond = ifStmt->cond;
846                        clause->body = ifStmt->else_;
[b9fa85b]847                        // ifStmt should be implicately deleted here.
[400b8be]848                        return clause;
[2b59f55]849                }
[400b8be]850                return catchClause;
[d76c588]851        }
852
[0bd3faf]853        const ast::WaitForStmt * Resolver::previsit( const ast::WaitForStmt * stmt ) {
[2773ab8]854                visit_children = false;
855
856                // Resolve all clauses first
857                for ( unsigned i = 0; i < stmt->clauses.size(); ++i ) {
[f6e6a55]858                        const ast::WaitForClause & clause = *stmt->clauses[i];
[2773ab8]859
860                        ast::TypeEnvironment env;
[3bc69f2]861                        CandidateFinder funcFinder( context, env );
[2773ab8]862
863                        // Find all candidates for a function in canonical form
[4a89b52]864                        funcFinder.find( clause.target, ResolveMode::withAdjustment() );
[2773ab8]865
866                        if ( funcFinder.candidates.empty() ) {
867                                stringstream ss;
868                                ss << "Use of undeclared indentifier '";
[c86b08d]869                                ss << clause.target.strict_as< ast::NameExpr >()->name;
[2773ab8]870                                ss << "' in call to waitfor";
871                                SemanticError( stmt->location, ss.str() );
872                        }
873
[f6e6a55]874                        if ( clause.target_args.empty() ) {
[ef5b828]875                                SemanticError( stmt->location,
[2773ab8]876                                        "Waitfor clause must have at least one mutex parameter");
877                        }
878
879                        // Find all alternatives for all arguments in canonical form
[ef5b828]880                        std::vector< CandidateFinder > argFinders =
[f6e6a55]881                                funcFinder.findSubExprs( clause.target_args );
[ef5b828]882
[2773ab8]883                        // List all combinations of arguments
884                        std::vector< CandidateList > possibilities;
885                        combos( argFinders.begin(), argFinders.end(), back_inserter( possibilities ) );
886
887                        // For every possible function:
[ef5b828]888                        // * try matching the arguments to the parameters, not the other way around because
[2773ab8]889                        //   more arguments than parameters
890                        CandidateList funcCandidates;
891                        std::vector< CandidateList > argsCandidates;
892                        SemanticErrorException errors;
893                        for ( CandidateRef & func : funcFinder.candidates ) {
894                                try {
[ef5b828]895                                        auto pointerType = dynamic_cast< const ast::PointerType * >(
[2773ab8]896                                                func->expr->result->stripReferences() );
897                                        if ( ! pointerType ) {
[ef5b828]898                                                SemanticError( stmt->location, func->expr->result.get(),
[2773ab8]899                                                        "candidate not viable: not a pointer type\n" );
900                                        }
901
902                                        auto funcType = pointerType->base.as< ast::FunctionType >();
903                                        if ( ! funcType ) {
[ef5b828]904                                                SemanticError( stmt->location, func->expr->result.get(),
[2773ab8]905                                                        "candidate not viable: not a function type\n" );
906                                        }
907
908                                        {
909                                                auto param    = funcType->params.begin();
910                                                auto paramEnd = funcType->params.end();
911
912                                                if( ! nextMutex( param, paramEnd ) ) {
[ef5b828]913                                                        SemanticError( stmt->location, funcType,
[2773ab8]914                                                                "candidate function not viable: no mutex parameters\n");
915                                                }
916                                        }
917
918                                        CandidateRef func2{ new Candidate{ *func } };
919                                        // strip reference from function
920                                        func2->expr = referenceToRvalueConversion( func->expr, func2->cost );
921
922                                        // Each argument must be matched with a parameter of the current candidate
923                                        for ( auto & argsList : possibilities ) {
924                                                try {
925                                                        // Declare data structures needed for resolution
926                                                        ast::OpenVarSet open;
927                                                        ast::AssertionSet need, have;
928                                                        ast::TypeEnvironment resultEnv{ func->env };
[ef5b828]929                                                        // Add all type variables as open so that those not used in the
[2773ab8]930                                                        // parameter list are still considered open
931                                                        resultEnv.add( funcType->forall );
932
933                                                        // load type variables from arguments into one shared space
934                                                        for ( auto & arg : argsList ) {
935                                                                resultEnv.simpleCombine( arg->env );
936                                                        }
937
938                                                        // Make sure we don't widen any existing bindings
939                                                        resultEnv.forbidWidening();
940
941                                                        // Find any unbound type variables
942                                                        resultEnv.extractOpenVars( open );
943
944                                                        auto param = funcType->params.begin();
945                                                        auto paramEnd = funcType->params.end();
946
947                                                        unsigned n_mutex_param = 0;
948
[ef5b828]949                                                        // For every argument of its set, check if it matches one of the
[2773ab8]950                                                        // parameters. The order is important
951                                                        for ( auto & arg : argsList ) {
952                                                                // Ignore non-mutex arguments
953                                                                if ( ! nextMutex( param, paramEnd ) ) {
954                                                                        // We ran out of parameters but still have arguments.
955                                                                        // This function doesn't match
[ef5b828]956                                                                        SemanticError( stmt->location, funcType,
[2773ab8]957                                                                                toString("candidate function not viable: too many mutex "
958                                                                                "arguments, expected ", n_mutex_param, "\n" ) );
959                                                                }
960
961                                                                ++n_mutex_param;
962
[4c2fe47]963                                                                // Check if the argument matches the parameter type in the current scope.
[954c954]964                                                                // ast::ptr< ast::Type > paramType = (*param)->get_type();
[4c2fe47]965
[ef5b828]966                                                                if (
967                                                                        ! unify(
[251ce80]968                                                                                arg->expr->result, *param, resultEnv, need, have, open )
[2773ab8]969                                                                ) {
970                                                                        // Type doesn't match
971                                                                        stringstream ss;
972                                                                        ss << "candidate function not viable: no known conversion "
973                                                                                "from '";
[954c954]974                                                                        ast::print( ss, *param );
[2773ab8]975                                                                        ss << "' to '";
976                                                                        ast::print( ss, arg->expr->result );
977                                                                        ss << "' with env '";
978                                                                        ast::print( ss, resultEnv );
979                                                                        ss << "'\n";
980                                                                        SemanticError( stmt->location, funcType, ss.str() );
981                                                                }
982
983                                                                ++param;
984                                                        }
985
986                                                        // All arguments match!
987
988                                                        // Check if parameters are missing
989                                                        if ( nextMutex( param, paramEnd ) ) {
990                                                                do {
991                                                                        ++n_mutex_param;
992                                                                        ++param;
993                                                                } while ( nextMutex( param, paramEnd ) );
994
[ef5b828]995                                                                // We ran out of arguments but still have parameters left; this
[2773ab8]996                                                                // function doesn't match
[ef5b828]997                                                                SemanticError( stmt->location, funcType,
[2773ab8]998                                                                        toString( "candidate function not viable: too few mutex "
999                                                                        "arguments, expected ", n_mutex_param, "\n" ) );
1000                                                        }
1001
1002                                                        // All parameters match!
1003
1004                                                        // Finish the expressions to tie in proper environments
1005                                                        finishExpr( func2->expr, resultEnv );
1006                                                        for ( CandidateRef & arg : argsList ) {
1007                                                                finishExpr( arg->expr, resultEnv );
1008                                                        }
1009
1010                                                        // This is a match, store it and save it for later
1011                                                        funcCandidates.emplace_back( std::move( func2 ) );
1012                                                        argsCandidates.emplace_back( std::move( argsList ) );
1013
1014                                                } catch ( SemanticErrorException & e ) {
1015                                                        errors.append( e );
1016                                                }
1017                                        }
1018                                } catch ( SemanticErrorException & e ) {
1019                                        errors.append( e );
1020                                }
1021                        }
1022
1023                        // Make sure correct number of arguments
1024                        if( funcCandidates.empty() ) {
[ef5b828]1025                                SemanticErrorException top( stmt->location,
[2773ab8]1026                                        "No alternatives for function in call to waitfor" );
1027                                top.append( errors );
1028                                throw top;
1029                        }
1030
1031                        if( argsCandidates.empty() ) {
[ef5b828]1032                                SemanticErrorException top( stmt->location,
1033                                        "No alternatives for arguments in call to waitfor" );
[2773ab8]1034                                top.append( errors );
1035                                throw top;
1036                        }
1037
1038                        if( funcCandidates.size() > 1 ) {
[ef5b828]1039                                SemanticErrorException top( stmt->location,
[2773ab8]1040                                        "Ambiguous function in call to waitfor" );
1041                                top.append( errors );
1042                                throw top;
1043                        }
1044                        if( argsCandidates.size() > 1 ) {
1045                                SemanticErrorException top( stmt->location,
1046                                        "Ambiguous arguments in call to waitfor" );
1047                                top.append( errors );
1048                                throw top;
1049                        }
1050                        // TODO: need to use findDeletedExpr to ensure no deleted identifiers are used.
1051
1052                        // build new clause
[f6e6a55]1053                        auto clause2 = new ast::WaitForClause( clause.location );
[ef5b828]1054
[c86b08d]1055                        clause2->target = funcCandidates.front()->expr;
[ef5b828]1056
[f6e6a55]1057                        clause2->target_args.reserve( clause.target_args.size() );
[6668a3e]1058                        const ast::StructDecl * decl_monitor = symtab.lookupStruct( "monitor$" );
[2773ab8]1059                        for ( auto arg : argsCandidates.front() ) {
[6668a3e]1060                                const auto & loc = stmt->location;
1061
1062                                ast::Expr * init = new ast::CastExpr( loc,
1063                                        new ast::UntypedExpr( loc,
1064                                                new ast::NameExpr( loc, "get_monitor" ),
1065                                                { arg->expr }
1066                                        ),
1067                                        new ast::PointerType(
1068                                                new ast::StructInstType(
1069                                                        decl_monitor
1070                                                )
1071                                        )
1072                                );
1073
[f6e6a55]1074                                clause2->target_args.emplace_back( findSingleExpression( init, context ) );
[2773ab8]1075                        }
1076
1077                        // Resolve the conditions as if it were an IfStmt, statements normally
[c86b08d]1078                        clause2->when_cond = findSingleExpression( clause.when_cond, context );
[f6e6a55]1079                        clause2->stmt = clause.stmt->accept( *visitor );
[2773ab8]1080
1081                        // set results into stmt
1082                        auto n = mutate( stmt );
[f6e6a55]1083                        n->clauses[i] = clause2;
[2773ab8]1084                        stmt = n;
1085                }
1086
[f6e6a55]1087                if ( stmt->timeout_stmt ) {
[2773ab8]1088                        // resolve the timeout as a size_t, the conditions like IfStmt, and stmts normally
[ef5b828]1089                        ast::ptr< ast::Type > target =
[2773ab8]1090                                new ast::BasicType{ ast::BasicType::LongLongUnsignedInt };
[f6e6a55]1091                        auto timeout_time = findSingleExpression( stmt->timeout_time, target, context );
1092                        auto timeout_cond = findSingleExpression( stmt->timeout_cond, context );
1093                        auto timeout_stmt = stmt->timeout_stmt->accept( *visitor );
[2773ab8]1094
1095                        // set results into stmt
1096                        auto n = mutate( stmt );
[f6e6a55]1097                        n->timeout_time = std::move( timeout_time );
1098                        n->timeout_cond = std::move( timeout_cond );
1099                        n->timeout_stmt = std::move( timeout_stmt );
[2773ab8]1100                        stmt = n;
1101                }
1102
[f6e6a55]1103                if ( stmt->else_stmt ) {
[2773ab8]1104                        // resolve the condition like IfStmt, stmts normally
[f6e6a55]1105                        auto else_cond = findSingleExpression( stmt->else_cond, context );
1106                        auto else_stmt = stmt->else_stmt->accept( *visitor );
[2773ab8]1107
1108                        // set results into stmt
1109                        auto n = mutate( stmt );
[f6e6a55]1110                        n->else_cond = std::move( else_cond );
1111                        n->else_stmt = std::move( else_stmt );
[2773ab8]1112                        stmt = n;
1113                }
1114
1115                return stmt;
[d76c588]1116        }
1117
[0bd3faf]1118        const ast::WithStmt * Resolver::previsit( const ast::WithStmt * withStmt ) {
[16ba4a6]1119                auto mutStmt = mutate(withStmt);
1120                resolveWithExprs(mutStmt->exprs, stmtsToAddBefore);
1121                return mutStmt;
1122        }
1123
[0bd3faf]1124        void Resolver::resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd) {
[16ba4a6]1125                for (auto & expr : exprs) {
1126                        // only struct- and union-typed expressions are viable candidates
[3bc69f2]1127                        expr = findKindExpression( expr, context, structOrUnion, "with expression" );
[16ba4a6]1128
1129                        // if with expression might be impure, create a temporary so that it is evaluated once
1130                        if ( Tuples::maybeImpure( expr ) ) {
1131                                static UniqueName tmpNamer( "_with_tmp_" );
1132                                const CodeLocation loc = expr->location;
1133                                auto tmp = new ast::ObjectDecl(loc, tmpNamer.newName(), expr->result, new ast::SingleInit(loc, expr ) );
1134                                expr = new ast::VariableExpr( loc, tmp );
1135                                stmtsToAdd.push_back( new ast::DeclStmt(loc, tmp ) );
1136                                if ( InitTweak::isConstructable( tmp->type ) ) {
1137                                        // generate ctor/dtor and resolve them
1138                                        tmp->init = InitTweak::genCtorInit( loc, tmp );
1139                                }
1140                                // since tmp is freshly created, this should modify tmp in-place
1141                                tmp->accept( *visitor );
1142                        }
[9e23b446]1143                        else if (expr->env && expr->env->empty()) {
1144                                expr = ast::mutate_field(expr.get(), &ast::Expr::env, nullptr);
1145                        }
[16ba4a6]1146                }
1147        }
[60aaa51d]1148
1149
[0bd3faf]1150        const ast::SingleInit * Resolver::previsit( const ast::SingleInit * singleInit ) {
[60aaa51d]1151                visit_children = false;
[ef5b828]1152                // resolve initialization using the possibilities as determined by the `currentObject`
[60aaa51d]1153                // cursor.
[ef5b828]1154                ast::ptr< ast::Expr > untyped = new ast::UntypedInitExpr{
[60aaa51d]1155                        singleInit->location, singleInit->value, currentObject.getOptions() };
[3bc69f2]1156                ast::ptr<ast::Expr> newExpr = findSingleExpression( untyped, context );
[60aaa51d]1157                const ast::InitExpr * initExpr = newExpr.strict_as< ast::InitExpr >();
1158
1159                // move cursor to the object that is actually initialized
1160                currentObject.setNext( initExpr->designation );
1161
1162                // discard InitExpr wrapper and retain relevant pieces.
[ef5b828]1163                // `initExpr` may have inferred params in the case where the expression specialized a
1164                // function pointer, and newExpr may already have inferParams of its own, so a simple
[60aaa51d]1165                // swap is not sufficient
1166                ast::Expr::InferUnion inferred = initExpr->inferred;
1167                swap_and_save_env( newExpr, initExpr->expr );
1168                newExpr.get_and_mutate()->inferred.splice( std::move(inferred) );
1169
[ef5b828]1170                // get the actual object's type (may not exactly match what comes back from the resolver
[60aaa51d]1171                // due to conversions)
1172                const ast::Type * initContext = currentObject.getCurrentType();
1173
[918e4165]1174                removeExtraneousCast( newExpr );
[60aaa51d]1175
1176                // check if actual object's type is char[]
1177                if ( auto at = dynamic_cast< const ast::ArrayType * >( initContext ) ) {
1178                        if ( isCharType( at->base ) ) {
1179                                // check if the resolved type is char*
1180                                if ( auto pt = newExpr->result.as< ast::PointerType >() ) {
1181                                        if ( isCharType( pt->base ) ) {
[ef5b828]1182                                                // strip cast if we're initializing a char[] with a char*
[60aaa51d]1183                                                // e.g. char x[] = "hello"
1184                                                if ( auto ce = newExpr.as< ast::CastExpr >() ) {
1185                                                        swap_and_save_env( newExpr, ce->arg );
1186                                                }
1187                                        }
1188                                }
1189                        }
1190                }
1191
1192                // move cursor to next object in preparation for next initializer
1193                currentObject.increment();
1194
1195                // set initializer expression to resolved expression
1196                return ast::mutate_field( singleInit, &ast::SingleInit::value, std::move(newExpr) );
[d76c588]1197        }
1198
[0bd3faf]1199        const ast::ListInit * Resolver::previsit( const ast::ListInit * listInit ) {
[60aaa51d]1200                // move cursor into brace-enclosed initializer-list
1201                currentObject.enterListInit( listInit->location );
1202
1203                assert( listInit->designations.size() == listInit->initializers.size() );
1204                for ( unsigned i = 0; i < listInit->designations.size(); ++i ) {
[ef5b828]1205                        // iterate designations and initializers in pairs, moving the cursor to the current
[60aaa51d]1206                        // designated object and resolving the initializer against that object
[2d11663]1207                        listInit = ast::mutate_field_index(
[ef5b828]1208                                listInit, &ast::ListInit::designations, i,
[2d11663]1209                                currentObject.findNext( listInit->designations[i] ) );
1210                        listInit = ast::mutate_field_index(
1211                                listInit, &ast::ListInit::initializers, i,
1212                                listInit->initializers[i]->accept( *visitor ) );
[60aaa51d]1213                }
1214
[2d11663]1215                // move cursor out of brace-enclosed initializer-list
1216                currentObject.exitListInit();
1217
[60aaa51d]1218                visit_children = false;
1219                return listInit;
[d76c588]1220        }
1221
[0bd3faf]1222        const ast::ConstructorInit * Resolver::previsit( const ast::ConstructorInit * ctorInit ) {
[2d11663]1223                visitor->maybe_accept( ctorInit, &ast::ConstructorInit::ctor );
1224                visitor->maybe_accept( ctorInit, &ast::ConstructorInit::dtor );
1225
1226                // found a constructor - can get rid of C-style initializer
1227                // xxx - Rob suggests this field is dead code
1228                ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::init, nullptr );
1229
[ef5b828]1230                // intrinsic single-parameter constructors and destructors do nothing. Since this was
1231                // implicitly generated, there's no way for it to have side effects, so get rid of it to
[2d11663]1232                // clean up generated code
1233                if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->ctor ) ) {
1234                        ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::ctor, nullptr );
1235                }
1236                if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->dtor ) ) {
1237                        ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::dtor, nullptr );
1238                }
1239
1240                return ctorInit;
[d76c588]1241        }
1242
[59c8dff]1243        const ast::EnumPosExpr * Resolver::previsit( const ast::EnumPosExpr * enumPos ) {
1244                visitor->maybe_accept( enumPos, &ast::EnumPosExpr::expr );
1245                return enumPos;
1246        }
1247
[0dd9a5e]1248        // suppress error on autogen functions and mark invalid autogen as deleted.
[0bd3faf]1249        bool Resolver::on_error(ast::ptr<ast::Decl> & decl) {
[0dd9a5e]1250                if (auto functionDecl = decl.as<ast::FunctionDecl>()) {
1251                        // xxx - can intrinsic gen ever fail?
[6668a3e]1252                        if (functionDecl->linkage == ast::Linkage::AutoGen) {
[0dd9a5e]1253                                auto mutDecl = mutate(functionDecl);
1254                                mutDecl->isDeleted = true;
1255                                mutDecl->stmts = nullptr;
1256                                decl = mutDecl;
1257                                return false;
1258                        }
1259                }
1260                return true;
1261        }
1262
[51b7345]1263} // namespace ResolvExpr
[a32b204]1264
1265// Local Variables: //
1266// tab-width: 4 //
1267// mode: c++ //
1268// compile-command: "make install" //
1269// End: //
Note: See TracBrowser for help on using the repository browser.