source: src/ResolvExpr/Resolver.cpp @ 64f3b9f

Last change on this file since 64f3b9f was 64f3b9f, checked in by Michael Brooks <mlbrooks@…>, 7 days ago

Fix support for partial autogen.

Partial autogen means that some lifecycle functions are possible to generate, and needed, while others are impossible to generate, but unneeded. It is a valid situation that a user can implicitly request.

Previous handling of "impossible to generate" left the function in a zombie state, where it could show up as an alternative later. This zombie state is problematic handling caused by a compiler bug. Without the fix, the added test fails by creating zombie states.

This change is also a prerequsite for an upcoming change to avoid gcc warnings by not emitting autogen forward declarations.

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