source: src/ResolvExpr/Resolver.cc@ 8e4aa05

ADT arm-eh ast-experimental enum forall-pointer-decay jacob/cs343-translation new-ast-unique-expr pthread-emulation qualifiedEnum
Last change on this file since 8e4aa05 was 7583c02, checked in by Fangren Yu <f37yu@…>, 5 years ago

partially improve #226: resolver environment size reduced to O(n)

generated code still has exponential size. should cache resolved implicits
and reuse thunks to reduce generated code size.
assertion fails cannot exit early and may have a minor performance
reduction.

  • Property mode set to 100644
File size: 76.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.cc --
8//
9// Author : Aaron B. Moss
10// Created On : Sun May 17 12:17:01 2015
11// Last Modified By : Andrew Beach
12// Last Modified On : Fri Mar 27 11:58:00 2020
13// Update Count : 242
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 "Alternative.h" // for Alternative, AltList
22#include "AlternativeFinder.h" // for AlternativeFinder, resolveIn...
23#include "Candidate.hpp"
24#include "CandidateFinder.hpp"
25#include "CurrentObject.h" // for CurrentObject
26#include "RenameVars.h" // for RenameVars, global_renamer
27#include "Resolver.h"
28#include "ResolveTypeof.h"
29#include "ResolvMode.h" // for ResolvMode
30#include "typeops.h" // for extractResultType
31#include "Unify.h" // for unify
32#include "CompilationState.h"
33#include "AST/Chain.hpp"
34#include "AST/Decl.hpp"
35#include "AST/Init.hpp"
36#include "AST/Pass.hpp"
37#include "AST/Print.hpp"
38#include "AST/SymbolTable.hpp"
39#include "AST/Type.hpp"
40#include "Common/PassVisitor.h" // for PassVisitor
41#include "Common/SemanticError.h" // for SemanticError
42#include "Common/Stats/ResolveTime.h" // for ResolveTime::start(), ResolveTime::stop()
43#include "Common/utility.h" // for ValueGuard, group_iterate
44#include "InitTweak/GenInit.h"
45#include "InitTweak/InitTweak.h" // for isIntrinsicSingleArgCallStmt
46#include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment
47#include "SymTab/Autogen.h" // for SizeType
48#include "SymTab/Indexer.h" // for Indexer
49#include "SymTab/Mangler.h" // for Mangler
50#include "SynTree/Declaration.h" // for ObjectDecl, TypeDecl, Declar...
51#include "SynTree/Expression.h" // for Expression, CastExpr, InitExpr
52#include "SynTree/Initializer.h" // for ConstructorInit, SingleInit
53#include "SynTree/Statement.h" // for ForStmt, Statement, BranchStmt
54#include "SynTree/Type.h" // for Type, BasicType, PointerType
55#include "SynTree/TypeSubstitution.h" // for TypeSubstitution
56#include "SynTree/Visitor.h" // for acceptAll, maybeAccept
57#include "Tuples/Tuples.h"
58#include "Validate/FindSpecialDecls.h" // for SizeType
59
60using namespace std;
61
62namespace ResolvExpr {
63 struct Resolver_old final : public WithIndexer, public WithGuards, public WithVisitorRef<Resolver_old>, public WithShortCircuiting, public WithStmtsToAdd {
64 Resolver_old() {}
65 Resolver_old( const SymTab::Indexer & other ) {
66 indexer = other;
67 }
68
69 void previsit( FunctionDecl * functionDecl );
70 void postvisit( FunctionDecl * functionDecl );
71 void previsit( ObjectDecl * objectDecll );
72 void previsit( EnumDecl * enumDecl );
73 void previsit( StaticAssertDecl * assertDecl );
74
75 void previsit( ArrayType * at );
76 void previsit( PointerType * at );
77
78 void previsit( ExprStmt * exprStmt );
79 void previsit( AsmExpr * asmExpr );
80 void previsit( AsmStmt * asmStmt );
81 void previsit( IfStmt * ifStmt );
82 void previsit( WhileStmt * whileStmt );
83 void previsit( ForStmt * forStmt );
84 void previsit( SwitchStmt * switchStmt );
85 void previsit( CaseStmt * caseStmt );
86 void previsit( BranchStmt * branchStmt );
87 void previsit( ReturnStmt * returnStmt );
88 void previsit( ThrowStmt * throwStmt );
89 void previsit( CatchStmt * catchStmt );
90 void postvisit( CatchStmt * catchStmt );
91 void previsit( WaitForStmt * stmt );
92
93 void previsit( SingleInit * singleInit );
94 void previsit( ListInit * listInit );
95 void previsit( ConstructorInit * ctorInit );
96 private:
97 typedef std::list< Initializer * >::iterator InitIterator;
98
99 template< typename PtrType >
100 void handlePtrType( PtrType * type );
101
102 void fallbackInit( ConstructorInit * ctorInit );
103
104 Type * functionReturn = nullptr;
105 CurrentObject currentObject = nullptr;
106 bool inEnumDecl = false;
107 };
108
109 struct ResolveWithExprs : public WithIndexer, public WithGuards, public WithVisitorRef<ResolveWithExprs>, public WithShortCircuiting, public WithStmtsToAdd {
110 void previsit( FunctionDecl * );
111 void previsit( WithStmt * );
112
113 void resolveWithExprs( std::list< Expression * > & withExprs, std::list< Statement * > & newStmts );
114 };
115
116 void resolve( std::list< Declaration * > translationUnit ) {
117 PassVisitor<Resolver_old> resolver;
118 acceptAll( translationUnit, resolver );
119 }
120
121 void resolveDecl( Declaration * decl, const SymTab::Indexer & indexer ) {
122 PassVisitor<Resolver_old> resolver( indexer );
123 maybeAccept( decl, resolver );
124 }
125
126 namespace {
127 struct DeleteFinder_old : public WithShortCircuiting {
128 DeletedExpr * delExpr = nullptr;
129 void previsit( DeletedExpr * expr ) {
130 if ( delExpr ) visit_children = false;
131 else delExpr = expr;
132 }
133
134 void previsit( Expression * ) {
135 if ( delExpr ) visit_children = false;
136 }
137 };
138 }
139
140 DeletedExpr * findDeletedExpr( Expression * expr ) {
141 PassVisitor<DeleteFinder_old> finder;
142 expr->accept( finder );
143 return finder.pass.delExpr;
144 }
145
146 namespace {
147 struct StripCasts_old {
148 Expression * postmutate( CastExpr * castExpr ) {
149 if ( castExpr->isGenerated && ResolvExpr::typesCompatible( castExpr->arg->result, castExpr->result, SymTab::Indexer() ) ) {
150 // generated cast is to the same type as its argument, so it's unnecessary -- remove it
151 Expression * expr = castExpr->arg;
152 castExpr->arg = nullptr;
153 std::swap( expr->env, castExpr->env );
154 return expr;
155 }
156 return castExpr;
157 }
158
159 static void strip( Expression *& expr ) {
160 PassVisitor<StripCasts_old> stripper;
161 expr = expr->acceptMutator( stripper );
162 }
163 };
164
165 void finishExpr( Expression *& expr, const TypeEnvironment & env, TypeSubstitution * oldenv = nullptr ) {
166 expr->env = oldenv ? oldenv->clone() : new TypeSubstitution;
167 env.makeSubstitution( *expr->env );
168 StripCasts_old::strip( expr ); // remove unnecessary casts that may be buried in an expression
169 }
170
171 void removeExtraneousCast( Expression *& expr, const SymTab::Indexer & indexer ) {
172 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
173 if ( typesCompatible( castExpr->arg->result, castExpr->result, indexer ) ) {
174 // cast is to the same type as its argument, so it's unnecessary -- remove it
175 expr = castExpr->arg;
176 castExpr->arg = nullptr;
177 std::swap( expr->env, castExpr->env );
178 delete castExpr;
179 }
180 }
181 }
182 } // namespace
183
184 namespace {
185 void findUnfinishedKindExpression(Expression * untyped, Alternative & alt, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, ResolvMode mode = ResolvMode{} ) {
186 assertf( untyped, "expected a non-null expression." );
187
188 // xxx - this isn't thread-safe, but should work until we parallelize the resolver
189 static unsigned recursion_level = 0;
190
191 ++recursion_level;
192 TypeEnvironment env;
193 AlternativeFinder finder( indexer, env );
194 finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode );
195 --recursion_level;
196
197 #if 0
198 if ( finder.get_alternatives().size() != 1 ) {
199 std::cerr << "untyped expr is ";
200 untyped->print( std::cerr );
201 std::cerr << std::endl << "alternatives are:";
202 for ( const Alternative & alt : finder.get_alternatives() ) {
203 alt.print( std::cerr );
204 } // for
205 } // if
206 #endif
207
208 // produce filtered list of alternatives
209 AltList candidates;
210 for ( Alternative & alt : finder.get_alternatives() ) {
211 if ( pred( alt ) ) {
212 candidates.push_back( std::move( alt ) );
213 }
214 }
215
216 // produce invalid error if no candidates
217 if ( candidates.empty() ) {
218 SemanticError( untyped, toString( "No reasonable alternatives for ", kindStr, (kindStr != "" ? " " : ""), "expression: ") );
219 }
220
221 // search for cheapest candidate
222 AltList winners;
223 bool seen_undeleted = false;
224 for ( unsigned i = 0; i < candidates.size(); ++i ) {
225 int c = winners.empty() ? -1 : candidates[i].cost.compare( winners.front().cost );
226
227 if ( c > 0 ) continue; // skip more expensive than winner
228
229 if ( c < 0 ) {
230 // reset on new cheapest
231 seen_undeleted = ! findDeletedExpr( candidates[i].expr );
232 winners.clear();
233 } else /* if ( c == 0 ) */ {
234 if ( findDeletedExpr( candidates[i].expr ) ) {
235 // skip deleted expression if already seen one equivalent-cost not
236 if ( seen_undeleted ) continue;
237 } else if ( ! seen_undeleted ) {
238 // replace list of equivalent-cost deleted expressions with one non-deleted
239 winners.clear();
240 seen_undeleted = true;
241 }
242 }
243
244 winners.emplace_back( std::move( candidates[i] ) );
245 }
246
247 // promote alternative.cvtCost to .cost
248 // xxx - I don't know why this is done, but I'm keeping the behaviour from findMinCost
249 for ( Alternative& winner : winners ) {
250 winner.cost = winner.cvtCost;
251 }
252
253 // produce ambiguous errors, if applicable
254 if ( winners.size() != 1 ) {
255 std::ostringstream stream;
256 stream << "Cannot choose between " << winners.size() << " alternatives for " << kindStr << (kindStr != "" ? " " : "") << "expression\n";
257 untyped->print( stream );
258 stream << " Alternatives are:\n";
259 printAlts( winners, stream, 1 );
260 SemanticError( untyped->location, stream.str() );
261 }
262
263 // single selected choice
264 Alternative& choice = winners.front();
265
266 // fail on only expression deleted
267 if ( ! seen_undeleted ) {
268 SemanticError( untyped->location, choice.expr, "Unique best alternative includes deleted identifier in " );
269 }
270
271 // xxx - check for ambiguous expressions
272
273 // output selected choice
274 alt = std::move( choice );
275 }
276
277 /// resolve `untyped` to the expression whose alternative satisfies `pred` with the lowest cost; kindStr is used for providing better error messages
278 void findKindExpression(Expression *& untyped, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, ResolvMode mode = ResolvMode{}) {
279 if ( ! untyped ) return;
280 Alternative choice;
281 findUnfinishedKindExpression( untyped, choice, indexer, kindStr, pred, mode );
282 finishExpr( choice.expr, choice.env, untyped->env );
283 delete untyped;
284 untyped = choice.expr;
285 choice.expr = nullptr;
286 }
287
288 bool standardAlternativeFilter( const Alternative & ) {
289 // currently don't need to filter, under normal circumstances.
290 // in the future, this may be useful for removing deleted expressions
291 return true;
292 }
293 } // namespace
294
295 // used in resolveTypeof
296 Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer ) {
297 TypeEnvironment env;
298 return resolveInVoidContext( expr, indexer, env );
299 }
300
301 Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer, TypeEnvironment & env ) {
302 // it's a property of the language that a cast expression has either 1 or 0 interpretations; if it has 0
303 // interpretations, an exception has already been thrown.
304 assertf( expr, "expected a non-null expression." );
305
306 CastExpr * untyped = new CastExpr( expr ); // cast to void
307 untyped->location = expr->location;
308
309 // set up and resolve expression cast to void
310 Alternative choice;
311 findUnfinishedKindExpression( untyped, choice, indexer, "", standardAlternativeFilter, ResolvMode::withAdjustment() );
312 CastExpr * castExpr = strict_dynamic_cast< CastExpr * >( choice.expr );
313 assert( castExpr );
314 env = std::move( choice.env );
315
316 // clean up resolved expression
317 Expression * ret = castExpr->arg;
318 castExpr->arg = nullptr;
319
320 // unlink the arg so that it isn't deleted twice at the end of the program
321 untyped->arg = nullptr;
322 return ret;
323 }
324
325 void findVoidExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {
326 resetTyVarRenaming();
327 TypeEnvironment env;
328 Expression * newExpr = resolveInVoidContext( untyped, indexer, env );
329 finishExpr( newExpr, env, untyped->env );
330 delete untyped;
331 untyped = newExpr;
332 }
333
334 void findSingleExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {
335 findKindExpression( untyped, indexer, "", standardAlternativeFilter );
336 }
337
338 void findSingleExpression( Expression *& untyped, Type * type, const SymTab::Indexer & indexer ) {
339 assert( untyped && type );
340 // transfer location to generated cast for error purposes
341 CodeLocation location = untyped->location;
342 untyped = new CastExpr( untyped, type );
343 untyped->location = location;
344 findSingleExpression( untyped, indexer );
345 removeExtraneousCast( untyped, indexer );
346 }
347
348 namespace {
349 bool isIntegralType( const Alternative & alt ) {
350 Type * type = alt.expr->result;
351 if ( dynamic_cast< EnumInstType * >( type ) ) {
352 return true;
353 } else if ( BasicType * bt = dynamic_cast< BasicType * >( type ) ) {
354 return bt->isInteger();
355 } else if ( dynamic_cast< ZeroType* >( type ) != nullptr || dynamic_cast< OneType* >( type ) != nullptr ) {
356 return true;
357 } else {
358 return false;
359 } // if
360 }
361
362 void findIntegralExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {
363 findKindExpression( untyped, indexer, "condition", isIntegralType );
364 }
365 }
366
367
368 bool isStructOrUnion( const Alternative & alt ) {
369 Type * t = alt.expr->result->stripReferences();
370 return dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t );
371 }
372
373 void resolveWithExprs( std::list< Declaration * > & translationUnit ) {
374 PassVisitor<ResolveWithExprs> resolver;
375 acceptAll( translationUnit, resolver );
376 }
377
378 void ResolveWithExprs::resolveWithExprs( std::list< Expression * > & withExprs, std::list< Statement * > & newStmts ) {
379 for ( Expression *& expr : withExprs ) {
380 // only struct- and union-typed expressions are viable candidates
381 findKindExpression( expr, indexer, "with statement", isStructOrUnion );
382
383 // if with expression might be impure, create a temporary so that it is evaluated once
384 if ( Tuples::maybeImpure( expr ) ) {
385 static UniqueName tmpNamer( "_with_tmp_" );
386 ObjectDecl * tmp = ObjectDecl::newObject( tmpNamer.newName(), expr->result->clone(), new SingleInit( expr ) );
387 expr = new VariableExpr( tmp );
388 newStmts.push_back( new DeclStmt( tmp ) );
389 if ( InitTweak::isConstructable( tmp->type ) ) {
390 // generate ctor/dtor and resolve them
391 tmp->init = InitTweak::genCtorInit( tmp );
392 tmp->accept( *visitor );
393 }
394 }
395 }
396 }
397
398 void ResolveWithExprs::previsit( WithStmt * withStmt ) {
399 resolveWithExprs( withStmt->exprs, stmtsToAddBefore );
400 }
401
402 void ResolveWithExprs::previsit( FunctionDecl * functionDecl ) {
403 {
404 // resolve with-exprs with parameters in scope and add any newly generated declarations to the
405 // front of the function body.
406 auto guard = makeFuncGuard( [this]() { indexer.enterScope(); }, [this](){ indexer.leaveScope(); } );
407 indexer.addFunctionType( functionDecl->type );
408 std::list< Statement * > newStmts;
409 resolveWithExprs( functionDecl->withExprs, newStmts );
410 if ( functionDecl->statements ) {
411 functionDecl->statements->kids.splice( functionDecl->statements->kids.begin(), newStmts );
412 } else {
413 assertf( functionDecl->withExprs.empty() && newStmts.empty(), "Function %s without a body has with-clause and/or generated with declarations.", functionDecl->name.c_str() );
414 }
415 }
416 }
417
418 void Resolver_old::previsit( ObjectDecl * objectDecl ) {
419 // To handle initialization of routine pointers, e.g., int (*fp)(int) = foo(), means that
420 // class-variable initContext is changed multiple time because the LHS is analysed twice.
421 // The second analysis changes initContext because of a function type can contain object
422 // declarations in the return and parameter types. So each value of initContext is
423 // retained, so the type on the first analysis is preserved and used for selecting the RHS.
424 GuardValue( currentObject );
425 currentObject = CurrentObject( objectDecl->get_type() );
426 if ( inEnumDecl && dynamic_cast< EnumInstType * >( objectDecl->get_type() ) ) {
427 // enumerator initializers should not use the enum type to initialize, since
428 // the enum type is still incomplete at this point. Use signed int instead.
429 currentObject = CurrentObject( new BasicType( Type::Qualifiers(), BasicType::SignedInt ) );
430 }
431 }
432
433 template< typename PtrType >
434 void Resolver_old::handlePtrType( PtrType * type ) {
435 if ( type->get_dimension() ) {
436 findSingleExpression( type->dimension, Validate::SizeType->clone(), indexer );
437 }
438 }
439
440 void Resolver_old::previsit( ArrayType * at ) {
441 handlePtrType( at );
442 }
443
444 void Resolver_old::previsit( PointerType * pt ) {
445 handlePtrType( pt );
446 }
447
448 void Resolver_old::previsit( FunctionDecl * functionDecl ) {
449#if 0
450 std::cerr << "resolver visiting functiondecl ";
451 functionDecl->print( std::cerr );
452 std::cerr << std::endl;
453#endif
454 GuardValue( functionReturn );
455 functionReturn = ResolvExpr::extractResultType( functionDecl->type );
456 }
457
458 void Resolver_old::postvisit( FunctionDecl * functionDecl ) {
459 // default value expressions have an environment which shouldn't be there and trips up
460 // later passes.
461 // xxx - it might be necessary to somehow keep the information from this environment, but I
462 // can't currently see how it's useful.
463 for ( Declaration * d : functionDecl->type->parameters ) {
464 if ( ObjectDecl * obj = dynamic_cast< ObjectDecl * >( d ) ) {
465 if ( SingleInit * init = dynamic_cast< SingleInit * >( obj->init ) ) {
466 delete init->value->env;
467 init->value->env = nullptr;
468 }
469 }
470 }
471 }
472
473 void Resolver_old::previsit( EnumDecl * ) {
474 // in case we decide to allow nested enums
475 GuardValue( inEnumDecl );
476 inEnumDecl = true;
477 }
478
479 void Resolver_old::previsit( StaticAssertDecl * assertDecl ) {
480 findIntegralExpression( assertDecl->condition, indexer );
481 }
482
483 void Resolver_old::previsit( ExprStmt * exprStmt ) {
484 visit_children = false;
485 assertf( exprStmt->expr, "ExprStmt has null Expression in resolver" );
486 findVoidExpression( exprStmt->expr, indexer );
487 }
488
489 void Resolver_old::previsit( AsmExpr * asmExpr ) {
490 visit_children = false;
491 findVoidExpression( asmExpr->operand, indexer );
492 }
493
494 void Resolver_old::previsit( AsmStmt * asmStmt ) {
495 visit_children = false;
496 acceptAll( asmStmt->get_input(), *visitor );
497 acceptAll( asmStmt->get_output(), *visitor );
498 }
499
500 void Resolver_old::previsit( IfStmt * ifStmt ) {
501 findIntegralExpression( ifStmt->condition, indexer );
502 }
503
504 void Resolver_old::previsit( WhileStmt * whileStmt ) {
505 findIntegralExpression( whileStmt->condition, indexer );
506 }
507
508 void Resolver_old::previsit( ForStmt * forStmt ) {
509 if ( forStmt->condition ) {
510 findIntegralExpression( forStmt->condition, indexer );
511 } // if
512
513 if ( forStmt->increment ) {
514 findVoidExpression( forStmt->increment, indexer );
515 } // if
516 }
517
518 void Resolver_old::previsit( SwitchStmt * switchStmt ) {
519 GuardValue( currentObject );
520 findIntegralExpression( switchStmt->condition, indexer );
521
522 currentObject = CurrentObject( switchStmt->condition->result );
523 }
524
525 void Resolver_old::previsit( CaseStmt * caseStmt ) {
526 if ( caseStmt->condition ) {
527 std::list< InitAlternative > initAlts = currentObject.getOptions();
528 assertf( initAlts.size() == 1, "SwitchStmt did not correctly resolve an integral expression." );
529 // must remove cast from case statement because RangeExpr cannot be cast.
530 Expression * newExpr = new CastExpr( caseStmt->condition, initAlts.front().type->clone() );
531 findSingleExpression( newExpr, indexer );
532 // case condition cannot have a cast in C, so it must be removed, regardless of whether it performs a conversion.
533 // Ideally we would perform the conversion internally here.
534 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( newExpr ) ) {
535 newExpr = castExpr->arg;
536 castExpr->arg = nullptr;
537 std::swap( newExpr->env, castExpr->env );
538 delete castExpr;
539 }
540 caseStmt->condition = newExpr;
541 }
542 }
543
544 void Resolver_old::previsit( BranchStmt * branchStmt ) {
545 visit_children = false;
546 // must resolve the argument for a computed goto
547 if ( branchStmt->get_type() == BranchStmt::Goto ) { // check for computed goto statement
548 if ( branchStmt->computedTarget ) {
549 // computed goto argument is void *
550 findSingleExpression( branchStmt->computedTarget, new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), indexer );
551 } // if
552 } // if
553 }
554
555 void Resolver_old::previsit( ReturnStmt * returnStmt ) {
556 visit_children = false;
557 if ( returnStmt->expr ) {
558 findSingleExpression( returnStmt->expr, functionReturn->clone(), indexer );
559 } // if
560 }
561
562 void Resolver_old::previsit( ThrowStmt * throwStmt ) {
563 visit_children = false;
564 // TODO: Replace *exception type with &exception type.
565 if ( throwStmt->get_expr() ) {
566 const StructDecl * exception_decl = indexer.lookupStruct( "__cfaehm_base_exception_t" );
567 assert( exception_decl );
568 Type * exceptType = new PointerType( noQualifiers, new StructInstType( noQualifiers, const_cast<StructDecl *>(exception_decl) ) );
569 findSingleExpression( throwStmt->expr, exceptType, indexer );
570 }
571 }
572
573 void Resolver_old::previsit( CatchStmt * catchStmt ) {
574 // Until we are very sure this invarent (ifs that move between passes have thenPart)
575 // holds, check it. This allows a check for when to decode the mangling.
576 if ( IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body ) ) {
577 assert( ifStmt->thenPart );
578 }
579 // Encode the catchStmt so the condition can see the declaration.
580 if ( catchStmt->cond ) {
581 IfStmt * ifStmt = new IfStmt( catchStmt->cond, nullptr, catchStmt->body );
582 catchStmt->cond = nullptr;
583 catchStmt->body = ifStmt;
584 }
585 }
586
587 void Resolver_old::postvisit( CatchStmt * catchStmt ) {
588 // Decode the catchStmt so everything is stored properly.
589 IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body );
590 if ( nullptr != ifStmt && nullptr == ifStmt->thenPart ) {
591 assert( ifStmt->condition );
592 assert( ifStmt->elsePart );
593 catchStmt->cond = ifStmt->condition;
594 catchStmt->body = ifStmt->elsePart;
595 ifStmt->condition = nullptr;
596 ifStmt->elsePart = nullptr;
597 delete ifStmt;
598 }
599 }
600
601 template< typename iterator_t >
602 inline bool advance_to_mutex( iterator_t & it, const iterator_t & end ) {
603 while( it != end && !(*it)->get_type()->get_mutex() ) {
604 it++;
605 }
606
607 return it != end;
608 }
609
610 void Resolver_old::previsit( WaitForStmt * stmt ) {
611 visit_children = false;
612
613 // Resolve all clauses first
614 for( auto& clause : stmt->clauses ) {
615
616 TypeEnvironment env;
617 AlternativeFinder funcFinder( indexer, env );
618
619 // Find all alternatives for a function in canonical form
620 funcFinder.findWithAdjustment( clause.target.function );
621
622 if ( funcFinder.get_alternatives().empty() ) {
623 stringstream ss;
624 ss << "Use of undeclared indentifier '";
625 ss << strict_dynamic_cast<NameExpr*>( clause.target.function )->name;
626 ss << "' in call to waitfor";
627 SemanticError( stmt->location, ss.str() );
628 }
629
630 if(clause.target.arguments.empty()) {
631 SemanticError( stmt->location, "Waitfor clause must have at least one mutex parameter");
632 }
633
634 // Find all alternatives for all arguments in canonical form
635 std::vector< AlternativeFinder > argAlternatives;
636 funcFinder.findSubExprs( clause.target.arguments.begin(), clause.target.arguments.end(), back_inserter( argAlternatives ) );
637
638 // List all combinations of arguments
639 std::vector< AltList > possibilities;
640 combos( argAlternatives.begin(), argAlternatives.end(), back_inserter( possibilities ) );
641
642 AltList func_candidates;
643 std::vector< AltList > args_candidates;
644
645 // For every possible function :
646 // try matching the arguments to the parameters
647 // not the other way around because we have more arguments than parameters
648 SemanticErrorException errors;
649 for ( Alternative & func : funcFinder.get_alternatives() ) {
650 try {
651 PointerType * pointer = dynamic_cast< PointerType* >( func.expr->get_result()->stripReferences() );
652 if( !pointer ) {
653 SemanticError( func.expr->get_result(), "candidate not viable: not a pointer type\n" );
654 }
655
656 FunctionType * function = dynamic_cast< FunctionType* >( pointer->get_base() );
657 if( !function ) {
658 SemanticError( pointer->get_base(), "candidate not viable: not a function type\n" );
659 }
660
661
662 {
663 auto param = function->parameters.begin();
664 auto param_end = function->parameters.end();
665
666 if( !advance_to_mutex( param, param_end ) ) {
667 SemanticError(function, "candidate function not viable: no mutex parameters\n");
668 }
669 }
670
671 Alternative newFunc( func );
672 // Strip reference from function
673 referenceToRvalueConversion( newFunc.expr, newFunc.cost );
674
675 // For all the set of arguments we have try to match it with the parameter of the current function alternative
676 for ( auto & argsList : possibilities ) {
677
678 try {
679 // Declare data structures need for resolution
680 OpenVarSet openVars;
681 AssertionSet resultNeed, resultHave;
682 TypeEnvironment resultEnv( func.env );
683 makeUnifiableVars( function, openVars, resultNeed );
684 // add all type variables as open variables now so that those not used in the parameter
685 // list are still considered open.
686 resultEnv.add( function->forall );
687
688 // Load type variables from arguemnts into one shared space
689 simpleCombineEnvironments( argsList.begin(), argsList.end(), resultEnv );
690
691 // Make sure we don't widen any existing bindings
692 resultEnv.forbidWidening();
693
694 // Find any unbound type variables
695 resultEnv.extractOpenVars( openVars );
696
697 auto param = function->parameters.begin();
698 auto param_end = function->parameters.end();
699
700 int n_mutex_param = 0;
701
702 // For every arguments of its set, check if it matches one of the parameter
703 // The order is important
704 for( auto & arg : argsList ) {
705
706 // Ignore non-mutex arguments
707 if( !advance_to_mutex( param, param_end ) ) {
708 // We ran out of parameters but still have arguments
709 // this function doesn't match
710 SemanticError( function, toString("candidate function not viable: too many mutex arguments, expected ", n_mutex_param, "\n" ));
711 }
712
713 n_mutex_param++;
714
715 // Check if the argument matches the parameter type in the current scope
716 if( ! unify( arg.expr->get_result(), (*param)->get_type(), resultEnv, resultNeed, resultHave, openVars, this->indexer ) ) {
717 // Type doesn't match
718 stringstream ss;
719 ss << "candidate function not viable: no known convertion from '";
720 (*param)->get_type()->print( ss );
721 ss << "' to '";
722 arg.expr->get_result()->print( ss );
723 ss << "' with env '";
724 resultEnv.print(ss);
725 ss << "'\n";
726 SemanticError( function, ss.str() );
727 }
728
729 param++;
730 }
731
732 // All arguments match !
733
734 // Check if parameters are missing
735 if( advance_to_mutex( param, param_end ) ) {
736 do {
737 n_mutex_param++;
738 param++;
739 } while( advance_to_mutex( param, param_end ) );
740
741 // We ran out of arguments but still have parameters left
742 // this function doesn't match
743 SemanticError( function, toString("candidate function not viable: too few mutex arguments, expected ", n_mutex_param, "\n" ));
744 }
745
746 // All parameters match !
747
748 // Finish the expressions to tie in the proper environments
749 finishExpr( newFunc.expr, resultEnv );
750 for( Alternative & alt : argsList ) {
751 finishExpr( alt.expr, resultEnv );
752 }
753
754 // This is a match store it and save it for later
755 func_candidates.push_back( newFunc );
756 args_candidates.push_back( argsList );
757
758 }
759 catch( SemanticErrorException & e ) {
760 errors.append( e );
761 }
762 }
763 }
764 catch( SemanticErrorException & e ) {
765 errors.append( e );
766 }
767 }
768
769 // Make sure we got the right number of arguments
770 if( func_candidates.empty() ) { SemanticErrorException top( stmt->location, "No alternatives for function in call to waitfor" ); top.append( errors ); throw top; }
771 if( args_candidates.empty() ) { SemanticErrorException top( stmt->location, "No alternatives for arguments in call to waitfor" ); top.append( errors ); throw top; }
772 if( func_candidates.size() > 1 ) { SemanticErrorException top( stmt->location, "Ambiguous function in call to waitfor" ); top.append( errors ); throw top; }
773 if( args_candidates.size() > 1 ) { SemanticErrorException top( stmt->location, "Ambiguous arguments in call to waitfor" ); top.append( errors ); throw top; }
774 // TODO: need to use findDeletedExpr to ensure no deleted identifiers are used.
775
776 // Swap the results from the alternative with the unresolved values.
777 // Alternatives will handle deletion on destruction
778 std::swap( clause.target.function, func_candidates.front().expr );
779 for( auto arg_pair : group_iterate( clause.target.arguments, args_candidates.front() ) ) {
780 std::swap ( std::get<0>( arg_pair), std::get<1>( arg_pair).expr );
781 }
782
783 // Resolve the conditions as if it were an IfStmt
784 // Resolve the statments normally
785 findSingleExpression( clause.condition, this->indexer );
786 clause.statement->accept( *visitor );
787 }
788
789
790 if( stmt->timeout.statement ) {
791 // Resolve the timeout as an size_t for now
792 // Resolve the conditions as if it were an IfStmt
793 // Resolve the statments normally
794 findSingleExpression( stmt->timeout.time, new BasicType( noQualifiers, BasicType::LongLongUnsignedInt ), this->indexer );
795 findSingleExpression( stmt->timeout.condition, this->indexer );
796 stmt->timeout.statement->accept( *visitor );
797 }
798
799 if( stmt->orelse.statement ) {
800 // Resolve the conditions as if it were an IfStmt
801 // Resolve the statments normally
802 findSingleExpression( stmt->orelse.condition, this->indexer );
803 stmt->orelse.statement->accept( *visitor );
804 }
805 }
806
807 bool isCharType( Type * t ) {
808 if ( BasicType * bt = dynamic_cast< BasicType * >( t ) ) {
809 return bt->get_kind() == BasicType::Char || bt->get_kind() == BasicType::SignedChar ||
810 bt->get_kind() == BasicType::UnsignedChar;
811 }
812 return false;
813 }
814
815 void Resolver_old::previsit( SingleInit * singleInit ) {
816 visit_children = false;
817 // resolve initialization using the possibilities as determined by the currentObject cursor
818 Expression * newExpr = new UntypedInitExpr( singleInit->value, currentObject.getOptions() );
819 findSingleExpression( newExpr, indexer );
820 InitExpr * initExpr = strict_dynamic_cast< InitExpr * >( newExpr );
821
822 // move cursor to the object that is actually initialized
823 currentObject.setNext( initExpr->get_designation() );
824
825 // discard InitExpr wrapper and retain relevant pieces
826 newExpr = initExpr->expr;
827 initExpr->expr = nullptr;
828 std::swap( initExpr->env, newExpr->env );
829 // InitExpr may have inferParams in the case where the expression specializes a function
830 // pointer, and newExpr may already have inferParams of its own, so a simple swap is not
831 // sufficient.
832 newExpr->spliceInferParams( initExpr );
833 delete initExpr;
834
835 // get the actual object's type (may not exactly match what comes back from the resolver
836 // due to conversions)
837 Type * initContext = currentObject.getCurrentType();
838
839 removeExtraneousCast( newExpr, indexer );
840
841 // check if actual object's type is char[]
842 if ( ArrayType * at = dynamic_cast< ArrayType * >( initContext ) ) {
843 if ( isCharType( at->get_base() ) ) {
844 // check if the resolved type is char *
845 if ( PointerType * pt = dynamic_cast< PointerType *>( newExpr->get_result() ) ) {
846 if ( isCharType( pt->get_base() ) ) {
847 if ( CastExpr * ce = dynamic_cast< CastExpr * >( newExpr ) ) {
848 // strip cast if we're initializing a char[] with a char *,
849 // e.g. char x[] = "hello";
850 newExpr = ce->get_arg();
851 ce->set_arg( nullptr );
852 std::swap( ce->env, newExpr->env );
853 delete ce;
854 }
855 }
856 }
857 }
858 }
859
860 // set initializer expr to resolved express
861 singleInit->value = newExpr;
862
863 // move cursor to next object in preparation for next initializer
864 currentObject.increment();
865 }
866
867 void Resolver_old::previsit( ListInit * listInit ) {
868 visit_children = false;
869 // move cursor into brace-enclosed initializer-list
870 currentObject.enterListInit();
871 // xxx - fix this so that the list isn't copied, iterator should be used to change current
872 // element
873 std::list<Designation *> newDesignations;
874 for ( auto p : group_iterate(listInit->get_designations(), listInit->get_initializers()) ) {
875 // iterate designations and initializers in pairs, moving the cursor to the current
876 // designated object and resolving the initializer against that object.
877 Designation * des = std::get<0>(p);
878 Initializer * init = std::get<1>(p);
879 newDesignations.push_back( currentObject.findNext( des ) );
880 init->accept( *visitor );
881 }
882 // set the set of 'resolved' designations and leave the brace-enclosed initializer-list
883 listInit->get_designations() = newDesignations; // xxx - memory management
884 currentObject.exitListInit();
885
886 // xxx - this part has not be folded into CurrentObject yet
887 // } else if ( TypeInstType * tt = dynamic_cast< TypeInstType * >( initContext ) ) {
888 // Type * base = tt->get_baseType()->get_base();
889 // if ( base ) {
890 // // know the implementation type, so try using that as the initContext
891 // ObjectDecl tmpObj( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, base->clone(), nullptr );
892 // currentObject = &tmpObj;
893 // visit( listInit );
894 // } else {
895 // // missing implementation type -- might be an unknown type variable, so try proceeding with the current init context
896 // Parent::visit( listInit );
897 // }
898 // } else {
899 }
900
901 // ConstructorInit - fall back on C-style initializer
902 void Resolver_old::fallbackInit( ConstructorInit * ctorInit ) {
903 // could not find valid constructor, or found an intrinsic constructor
904 // fall back on C-style initializer
905 delete ctorInit->get_ctor();
906 ctorInit->set_ctor( nullptr );
907 delete ctorInit->get_dtor();
908 ctorInit->set_dtor( nullptr );
909 maybeAccept( ctorInit->get_init(), *visitor );
910 }
911
912 // needs to be callable from outside the resolver, so this is a standalone function
913 void resolveCtorInit( ConstructorInit * ctorInit, const SymTab::Indexer & indexer ) {
914 assert( ctorInit );
915 PassVisitor<Resolver_old> resolver( indexer );
916 ctorInit->accept( resolver );
917 }
918
919 void resolveStmtExpr( StmtExpr * stmtExpr, const SymTab::Indexer & indexer ) {
920 assert( stmtExpr );
921 PassVisitor<Resolver_old> resolver( indexer );
922 stmtExpr->accept( resolver );
923 stmtExpr->computeResult();
924 // xxx - aggregate the environments from all statements? Possibly in AlternativeFinder instead?
925 }
926
927 void Resolver_old::previsit( ConstructorInit * ctorInit ) {
928 visit_children = false;
929 // xxx - fallback init has been removed => remove fallbackInit function and remove complexity from FixInit and remove C-init from ConstructorInit
930 maybeAccept( ctorInit->ctor, *visitor );
931 maybeAccept( ctorInit->dtor, *visitor );
932
933 // found a constructor - can get rid of C-style initializer
934 delete ctorInit->init;
935 ctorInit->init = nullptr;
936
937 // intrinsic single parameter constructors and destructors do nothing. Since this was
938 // implicitly generated, there's no way for it to have side effects, so get rid of it
939 // to clean up generated code.
940 if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->ctor ) ) {
941 delete ctorInit->ctor;
942 ctorInit->ctor = nullptr;
943 }
944
945 if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->dtor ) ) {
946 delete ctorInit->dtor;
947 ctorInit->dtor = nullptr;
948 }
949
950 // xxx - todo -- what about arrays?
951 // if ( dtor == nullptr && InitTweak::isIntrinsicCallStmt( ctorInit->get_ctor() ) ) {
952 // // can reduce the constructor down to a SingleInit using the
953 // // second argument from the ctor call, since
954 // delete ctorInit->get_ctor();
955 // ctorInit->set_ctor( nullptr );
956
957 // Expression * arg =
958 // ctorInit->set_init( new SingleInit( arg ) );
959 // }
960 }
961
962 ///////////////////////////////////////////////////////////////////////////
963 //
964 // *** NEW RESOLVER ***
965 //
966 ///////////////////////////////////////////////////////////////////////////
967
968 namespace {
969 /// Finds deleted expressions in an expression tree
970 struct DeleteFinder_new final : public ast::WithShortCircuiting, public ast::WithVisitorRef<DeleteFinder_new> {
971 const ast::DeletedExpr * result = nullptr;
972
973 void previsit( const ast::DeletedExpr * expr ) {
974 if ( result ) { visit_children = false; }
975 else { result = expr; }
976 }
977
978 void previsit( const ast::Expr * expr ) {
979 if ( result ) { visit_children = false; }
980 if (expr->inferred.hasParams()) {
981 for (auto & imp : expr->inferred.inferParams() ) {
982 imp.second.expr->accept(*visitor);
983 }
984 }
985 }
986 };
987 } // anonymous namespace
988 /// Check if this expression is or includes a deleted expression
989 const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ) {
990 return ast::Pass<DeleteFinder_new>::read( expr );
991 }
992
993 namespace {
994 /// always-accept candidate filter
995 bool anyCandidate( const Candidate & ) { return true; }
996
997 /// Calls the CandidateFinder and finds the single best candidate
998 CandidateRef findUnfinishedKindExpression(
999 const ast::Expr * untyped, const ast::SymbolTable & symtab, const std::string & kind,
1000 std::function<bool(const Candidate &)> pred = anyCandidate, ResolvMode mode = {}
1001 ) {
1002 if ( ! untyped ) return nullptr;
1003
1004 // xxx - this isn't thread-safe, but should work until we parallelize the resolver
1005 static unsigned recursion_level = 0;
1006
1007 ++recursion_level;
1008 ast::TypeEnvironment env;
1009 CandidateFinder finder{ symtab, env };
1010 finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode );
1011 --recursion_level;
1012
1013 // produce a filtered list of candidates
1014 CandidateList candidates;
1015 for ( auto & cand : finder.candidates ) {
1016 if ( pred( *cand ) ) { candidates.emplace_back( cand ); }
1017 }
1018
1019 // produce invalid error if no candidates
1020 if ( candidates.empty() ) {
1021 SemanticError( untyped,
1022 toString( "No reasonable alternatives for ", kind, (kind != "" ? " " : ""),
1023 "expression: ") );
1024 }
1025
1026 // search for cheapest candidate
1027 CandidateList winners;
1028 bool seen_undeleted = false;
1029 for ( CandidateRef & cand : candidates ) {
1030 int c = winners.empty() ? -1 : cand->cost.compare( winners.front()->cost );
1031
1032 if ( c > 0 ) continue; // skip more expensive than winner
1033
1034 if ( c < 0 ) {
1035 // reset on new cheapest
1036 seen_undeleted = ! findDeletedExpr( cand->expr );
1037 winners.clear();
1038 } else /* if ( c == 0 ) */ {
1039 if ( findDeletedExpr( cand->expr ) ) {
1040 // skip deleted expression if already seen one equivalent-cost not
1041 if ( seen_undeleted ) continue;
1042 } else if ( ! seen_undeleted ) {
1043 // replace list of equivalent-cost deleted expressions with one non-deleted
1044 winners.clear();
1045 seen_undeleted = true;
1046 }
1047 }
1048
1049 winners.emplace_back( std::move( cand ) );
1050 }
1051
1052 // promote candidate.cvtCost to .cost
1053 promoteCvtCost( winners );
1054
1055 // produce ambiguous errors, if applicable
1056 if ( winners.size() != 1 ) {
1057 std::ostringstream stream;
1058 stream << "Cannot choose between " << winners.size() << " alternatives for "
1059 << kind << (kind != "" ? " " : "") << "expression\n";
1060 ast::print( stream, untyped );
1061 stream << " Alternatives are:\n";
1062 print( stream, winners, 1 );
1063 SemanticError( untyped->location, stream.str() );
1064 }
1065
1066 // single selected choice
1067 CandidateRef & choice = winners.front();
1068
1069 // fail on only expression deleted
1070 if ( ! seen_undeleted ) {
1071 SemanticError( untyped->location, choice->expr.get(), "Unique best alternative "
1072 "includes deleted identifier in " );
1073 }
1074
1075 return std::move( choice );
1076 }
1077
1078 /// Strips extraneous casts out of an expression
1079 struct StripCasts_new final {
1080 const ast::Expr * postvisit( const ast::CastExpr * castExpr ) {
1081 if (
1082 castExpr->isGenerated == ast::GeneratedCast
1083 && typesCompatible( castExpr->arg->result, castExpr->result )
1084 ) {
1085 // generated cast is the same type as its argument, remove it after keeping env
1086 return ast::mutate_field(
1087 castExpr->arg.get(), &ast::Expr::env, castExpr->env );
1088 }
1089 return castExpr;
1090 }
1091
1092 static void strip( ast::ptr< ast::Expr > & expr ) {
1093 ast::Pass< StripCasts_new > stripper;
1094 expr = expr->accept( stripper );
1095 }
1096 };
1097
1098 /// Swaps argument into expression pointer, saving original environment
1099 void swap_and_save_env( ast::ptr< ast::Expr > & expr, const ast::Expr * newExpr ) {
1100 ast::ptr< ast::TypeSubstitution > env = expr->env;
1101 expr.set_and_mutate( newExpr )->env = env;
1102 }
1103
1104 /// Removes cast to type of argument (unlike StripCasts, also handles non-generated casts)
1105 void removeExtraneousCast( ast::ptr<ast::Expr> & expr, const ast::SymbolTable & symtab ) {
1106 if ( const ast::CastExpr * castExpr = expr.as< ast::CastExpr >() ) {
1107 if ( typesCompatible( castExpr->arg->result, castExpr->result, symtab ) ) {
1108 // cast is to the same type as its argument, remove it
1109 swap_and_save_env( expr, castExpr->arg );
1110 }
1111 }
1112 }
1113
1114
1115 } // anonymous namespace
1116/// Establish post-resolver invariants for expressions
1117 void finishExpr(
1118 ast::ptr< ast::Expr > & expr, const ast::TypeEnvironment & env,
1119 const ast::TypeSubstitution * oldenv = nullptr
1120 ) {
1121 // set up new type substitution for expression
1122 ast::ptr< ast::TypeSubstitution > newenv =
1123 oldenv ? oldenv : new ast::TypeSubstitution{};
1124 env.writeToSubstitution( *newenv.get_and_mutate() );
1125 expr.get_and_mutate()->env = std::move( newenv );
1126 // remove unncecessary casts
1127 StripCasts_new::strip( expr );
1128 }
1129
1130 ast::ptr< ast::Expr > resolveInVoidContext(
1131 const ast::Expr * expr, const ast::SymbolTable & symtab, ast::TypeEnvironment & env
1132 ) {
1133 assertf( expr, "expected a non-null expression" );
1134
1135 // set up and resolve expression cast to void
1136 ast::ptr< ast::CastExpr > untyped = new ast::CastExpr{ expr };
1137 CandidateRef choice = findUnfinishedKindExpression(
1138 untyped, symtab, "", anyCandidate, ResolvMode::withAdjustment() );
1139
1140 // a cast expression has either 0 or 1 interpretations (by language rules);
1141 // if 0, an exception has already been thrown, and this code will not run
1142 const ast::CastExpr * castExpr = choice->expr.strict_as< ast::CastExpr >();
1143 env = std::move( choice->env );
1144
1145 return castExpr->arg;
1146 }
1147
1148 /// Resolve `untyped` to the expression whose candidate is the best match for a `void`
1149 /// context.
1150 ast::ptr< ast::Expr > findVoidExpression(
1151 const ast::Expr * untyped, const ast::SymbolTable & symtab
1152 ) {
1153 ast::TypeEnvironment env;
1154 ast::ptr< ast::Expr > newExpr = resolveInVoidContext( untyped, symtab, env );
1155 finishExpr( newExpr, env, untyped->env );
1156 return newExpr;
1157 }
1158
1159 namespace {
1160
1161
1162 /// resolve `untyped` to the expression whose candidate satisfies `pred` with the
1163 /// lowest cost, returning the resolved version
1164 ast::ptr< ast::Expr > findKindExpression(
1165 const ast::Expr * untyped, const ast::SymbolTable & symtab,
1166 std::function<bool(const Candidate &)> pred = anyCandidate,
1167 const std::string & kind = "", ResolvMode mode = {}
1168 ) {
1169 if ( ! untyped ) return {};
1170 CandidateRef choice =
1171 findUnfinishedKindExpression( untyped, symtab, kind, pred, mode );
1172 ResolvExpr::finishExpr( choice->expr, choice->env, untyped->env );
1173 return std::move( choice->expr );
1174 }
1175
1176 /// Resolve `untyped` to the single expression whose candidate is the best match
1177 ast::ptr< ast::Expr > findSingleExpression(
1178 const ast::Expr * untyped, const ast::SymbolTable & symtab
1179 ) {
1180 Stats::ResolveTime::start( untyped );
1181 auto res = findKindExpression( untyped, symtab );
1182 Stats::ResolveTime::stop();
1183 return res;
1184 }
1185 } // anonymous namespace
1186
1187 ast::ptr< ast::Expr > findSingleExpression(
1188 const ast::Expr * untyped, const ast::Type * type, const ast::SymbolTable & symtab
1189 ) {
1190 assert( untyped && type );
1191 ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped, type };
1192 ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, symtab );
1193 removeExtraneousCast( newExpr, symtab );
1194 return newExpr;
1195 }
1196
1197 namespace {
1198 bool structOrUnion( const Candidate & i ) {
1199 const ast::Type * t = i.expr->result->stripReferences();
1200 return dynamic_cast< const ast::StructInstType * >( t ) || dynamic_cast< const ast::UnionInstType * >( t );
1201 }
1202 /// Predicate for "Candidate has integral type"
1203 bool hasIntegralType( const Candidate & i ) {
1204 const ast::Type * type = i.expr->result;
1205
1206 if ( auto bt = dynamic_cast< const ast::BasicType * >( type ) ) {
1207 return bt->isInteger();
1208 } else if (
1209 dynamic_cast< const ast::EnumInstType * >( type )
1210 || dynamic_cast< const ast::ZeroType * >( type )
1211 || dynamic_cast< const ast::OneType * >( type )
1212 ) {
1213 return true;
1214 } else return false;
1215 }
1216
1217 /// Resolve `untyped` as an integral expression, returning the resolved version
1218 ast::ptr< ast::Expr > findIntegralExpression(
1219 const ast::Expr * untyped, const ast::SymbolTable & symtab
1220 ) {
1221 return findKindExpression( untyped, symtab, hasIntegralType, "condition" );
1222 }
1223
1224 /// check if a type is a character type
1225 bool isCharType( const ast::Type * t ) {
1226 if ( auto bt = dynamic_cast< const ast::BasicType * >( t ) ) {
1227 return bt->kind == ast::BasicType::Char
1228 || bt->kind == ast::BasicType::SignedChar
1229 || bt->kind == ast::BasicType::UnsignedChar;
1230 }
1231 return false;
1232 }
1233
1234 /// Advance a type itertor to the next mutex parameter
1235 template<typename Iter>
1236 inline bool nextMutex( Iter & it, const Iter & end ) {
1237 while ( it != end && ! (*it)->is_mutex() ) { ++it; }
1238 return it != end;
1239 }
1240 }
1241
1242 class Resolver_new final
1243 : public ast::WithSymbolTable, public ast::WithGuards,
1244 public ast::WithVisitorRef<Resolver_new>, public ast::WithShortCircuiting,
1245 public ast::WithStmtsToAdd<> {
1246
1247 ast::ptr< ast::Type > functionReturn = nullptr;
1248 ast::CurrentObject currentObject;
1249 // for work previously in GenInit
1250 static InitTweak::ManagedTypes_new managedTypes;
1251
1252 bool inEnumDecl = false;
1253
1254 public:
1255 static size_t traceId;
1256 Resolver_new() = default;
1257 Resolver_new( const ast::SymbolTable & syms ) { symtab = syms; }
1258
1259 const ast::FunctionDecl * previsit( const ast::FunctionDecl * );
1260 const ast::FunctionDecl * postvisit( const ast::FunctionDecl * );
1261 const ast::ObjectDecl * previsit( const ast::ObjectDecl * );
1262 void previsit( const ast::AggregateDecl * );
1263 void previsit( const ast::StructDecl * );
1264 void previsit( const ast::EnumDecl * );
1265 const ast::StaticAssertDecl * previsit( const ast::StaticAssertDecl * );
1266
1267 const ast::ArrayType * previsit( const ast::ArrayType * );
1268 const ast::PointerType * previsit( const ast::PointerType * );
1269
1270 const ast::ExprStmt * previsit( const ast::ExprStmt * );
1271 const ast::AsmExpr * previsit( const ast::AsmExpr * );
1272 const ast::AsmStmt * previsit( const ast::AsmStmt * );
1273 const ast::IfStmt * previsit( const ast::IfStmt * );
1274 const ast::WhileStmt * previsit( const ast::WhileStmt * );
1275 const ast::ForStmt * previsit( const ast::ForStmt * );
1276 const ast::SwitchStmt * previsit( const ast::SwitchStmt * );
1277 const ast::CaseStmt * previsit( const ast::CaseStmt * );
1278 const ast::BranchStmt * previsit( const ast::BranchStmt * );
1279 const ast::ReturnStmt * previsit( const ast::ReturnStmt * );
1280 const ast::ThrowStmt * previsit( const ast::ThrowStmt * );
1281 const ast::CatchStmt * previsit( const ast::CatchStmt * );
1282 const ast::CatchStmt * postvisit( const ast::CatchStmt * );
1283 const ast::WaitForStmt * previsit( const ast::WaitForStmt * );
1284 const ast::WithStmt * previsit( const ast::WithStmt * );
1285
1286 const ast::SingleInit * previsit( const ast::SingleInit * );
1287 const ast::ListInit * previsit( const ast::ListInit * );
1288 const ast::ConstructorInit * previsit( const ast::ConstructorInit * );
1289
1290 void resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd);
1291
1292 void beginScope() { managedTypes.beginScope(); }
1293 void endScope() { managedTypes.endScope(); }
1294 bool on_error(ast::ptr<ast::Decl> & decl);
1295 };
1296 // size_t Resolver_new::traceId = Stats::Heap::new_stacktrace_id("Resolver");
1297
1298 InitTweak::ManagedTypes_new Resolver_new::managedTypes;
1299
1300 void resolve( ast::TranslationUnit& translationUnit ) {
1301 ast::Pass< Resolver_new >::run( translationUnit );
1302 }
1303
1304 ast::ptr< ast::Init > resolveCtorInit(
1305 const ast::ConstructorInit * ctorInit, const ast::SymbolTable & symtab
1306 ) {
1307 assert( ctorInit );
1308 ast::Pass< Resolver_new > resolver{ symtab };
1309 return ctorInit->accept( resolver );
1310 }
1311
1312 const ast::Expr * resolveStmtExpr(
1313 const ast::StmtExpr * stmtExpr, const ast::SymbolTable & symtab
1314 ) {
1315 assert( stmtExpr );
1316 ast::Pass< Resolver_new > resolver{ symtab };
1317 auto ret = mutate(stmtExpr->accept(resolver));
1318 strict_dynamic_cast< ast::StmtExpr * >( ret )->computeResult();
1319 return ret;
1320 }
1321
1322 namespace {
1323 const ast::Attribute * handleAttribute(const CodeLocation & loc, const ast::Attribute * attr, const ast::SymbolTable & symtab) {
1324 std::string name = attr->normalizedName();
1325 if (name == "constructor" || name == "destructor") {
1326 if (attr->params.size() == 1) {
1327 auto arg = attr->params.front();
1328 auto resolved = ResolvExpr::findSingleExpression( arg, new ast::BasicType( ast::BasicType::LongLongSignedInt ), symtab );
1329 auto result = eval(arg);
1330
1331 auto mutAttr = mutate(attr);
1332 mutAttr->params.front() = resolved;
1333 if (! result.second) {
1334 SemanticWarning(loc, Warning::GccAttributes,
1335 toCString( name, " priorities must be integers from 0 to 65535 inclusive: ", arg ) );
1336 }
1337 else {
1338 auto priority = result.first;
1339 if (priority < 101) {
1340 SemanticWarning(loc, Warning::GccAttributes,
1341 toCString( name, " priorities from 0 to 100 are reserved for the implementation" ) );
1342 } else if (priority < 201 && ! buildingLibrary()) {
1343 SemanticWarning(loc, Warning::GccAttributes,
1344 toCString( name, " priorities from 101 to 200 are reserved for the implementation" ) );
1345 }
1346 }
1347 return mutAttr;
1348 } else if (attr->params.size() > 1) {
1349 SemanticWarning(loc, Warning::GccAttributes, toCString( "too many arguments to ", name, " attribute" ) );
1350 } else {
1351 SemanticWarning(loc, Warning::GccAttributes, toCString( "too few arguments to ", name, " attribute" ) );
1352 }
1353 }
1354 return attr;
1355 }
1356 }
1357
1358 const ast::FunctionDecl * Resolver_new::previsit( const ast::FunctionDecl * functionDecl ) {
1359 GuardValue( functionReturn );
1360
1361 assert (functionDecl->unique());
1362 if (!functionDecl->has_body() && !functionDecl->withExprs.empty()) {
1363 SemanticError(functionDecl->location, functionDecl, "Function without body has with declarations");
1364 }
1365
1366 if (!functionDecl->isTypeFixed) {
1367 auto mutDecl = mutate(functionDecl);
1368 auto mutType = mutDecl->type.get_and_mutate();
1369
1370 for (auto & attr: mutDecl->attributes) {
1371 attr = handleAttribute(mutDecl->location, attr, symtab);
1372 }
1373
1374 // handle assertions
1375
1376 symtab.enterScope();
1377 mutType->forall.clear();
1378 mutType->assertions.clear();
1379 for (auto & typeParam : mutDecl->type_params) {
1380 symtab.addType(typeParam);
1381 mutType->forall.emplace_back(new ast::TypeInstType(typeParam->name, typeParam));
1382 }
1383 for (auto & asst : mutDecl->assertions) {
1384 asst = fixObjectType(asst.strict_as<ast::ObjectDecl>(), symtab);
1385 symtab.addId(asst);
1386 mutType->assertions.emplace_back(new ast::VariableExpr(functionDecl->location, asst));
1387 }
1388
1389 // temporarily adds params to symbol table.
1390 // actual scoping rules for params and withexprs differ - see Pass::visit(FunctionDecl)
1391
1392 std::vector<ast::ptr<ast::Type>> paramTypes;
1393 std::vector<ast::ptr<ast::Type>> returnTypes;
1394
1395 for (auto & param : mutDecl->params) {
1396 param = fixObjectType(param.strict_as<ast::ObjectDecl>(), symtab);
1397 symtab.addId(param);
1398 paramTypes.emplace_back(param->get_type());
1399 }
1400 for (auto & ret : mutDecl->returns) {
1401 ret = fixObjectType(ret.strict_as<ast::ObjectDecl>(), symtab);
1402 returnTypes.emplace_back(ret->get_type());
1403 }
1404 // since function type in decl is just a view of param types, need to update that as well
1405 mutType->params = std::move(paramTypes);
1406 mutType->returns = std::move(returnTypes);
1407
1408 auto renamedType = strict_dynamic_cast<const ast::FunctionType *>(renameTyVars(mutType, RenameMode::GEN_EXPR_ID));
1409
1410 std::list<ast::ptr<ast::Stmt>> newStmts;
1411 resolveWithExprs (mutDecl->withExprs, newStmts);
1412
1413 if (mutDecl->stmts) {
1414 auto mutStmt = mutDecl->stmts.get_and_mutate();
1415 mutStmt->kids.splice(mutStmt->kids.begin(), std::move(newStmts));
1416 mutDecl->stmts = mutStmt;
1417 }
1418
1419 symtab.leaveScope();
1420
1421 mutDecl->type = renamedType;
1422 mutDecl->mangleName = Mangle::mangle(mutDecl);
1423 mutDecl->isTypeFixed = true;
1424 functionDecl = mutDecl;
1425 }
1426 managedTypes.handleDWT(functionDecl);
1427
1428 functionReturn = extractResultType( functionDecl->type );
1429 return functionDecl;
1430 }
1431
1432 const ast::FunctionDecl * Resolver_new::postvisit( const ast::FunctionDecl * functionDecl ) {
1433 // default value expressions have an environment which shouldn't be there and trips up
1434 // later passes.
1435 assert( functionDecl->unique() );
1436 ast::FunctionType * mutType = mutate( functionDecl->type.get() );
1437
1438 for ( unsigned i = 0 ; i < mutType->params.size() ; ++i ) {
1439 if ( const ast::ObjectDecl * obj = mutType->params[i].as< ast::ObjectDecl >() ) {
1440 if ( const ast::SingleInit * init = obj->init.as< ast::SingleInit >() ) {
1441 if ( init->value->env == nullptr ) continue;
1442 // clone initializer minus the initializer environment
1443 auto mutParam = mutate( mutType->params[i].strict_as< ast::ObjectDecl >() );
1444 auto mutInit = mutate( mutParam->init.strict_as< ast::SingleInit >() );
1445 auto mutValue = mutate( mutInit->value.get() );
1446
1447 mutValue->env = nullptr;
1448 mutInit->value = mutValue;
1449 mutParam->init = mutInit;
1450 mutType->params[i] = mutParam;
1451
1452 assert( ! mutType->params[i].strict_as< ast::ObjectDecl >()->init.strict_as< ast::SingleInit >()->value->env);
1453 }
1454 }
1455 }
1456 mutate_field(functionDecl, &ast::FunctionDecl::type, mutType);
1457 return functionDecl;
1458 }
1459
1460 const ast::ObjectDecl * Resolver_new::previsit( const ast::ObjectDecl * objectDecl ) {
1461 // To handle initialization of routine pointers [e.g. int (*fp)(int) = foo()],
1462 // class-variable `initContext` is changed multiple times because the LHS is analyzed
1463 // twice. The second analysis changes `initContext` because a function type can contain
1464 // object declarations in the return and parameter types. Therefore each value of
1465 // `initContext` is retained so the type on the first analysis is preserved and used for
1466 // selecting the RHS.
1467 GuardValue( currentObject );
1468
1469 if ( inEnumDecl && dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() ) ) {
1470 // enumerator initializers should not use the enum type to initialize, since the
1471 // enum type is still incomplete at this point. Use `int` instead.
1472 objectDecl = fixObjectType(objectDecl, symtab);
1473 currentObject = ast::CurrentObject{
1474 objectDecl->location, new ast::BasicType{ ast::BasicType::SignedInt } };
1475 }
1476 else {
1477 if (!objectDecl->isTypeFixed) {
1478 auto newDecl = fixObjectType(objectDecl, symtab);
1479 auto mutDecl = mutate(newDecl);
1480
1481 // generate CtorInit wrapper when necessary.
1482 // in certain cases, fixObjectType is called before reaching
1483 // this object in visitor pass, thus disabling CtorInit codegen.
1484 // this happens on aggregate members and function parameters.
1485 if ( InitTweak::tryConstruct( mutDecl ) && ( managedTypes.isManaged( mutDecl ) || ((! isInFunction() || mutDecl->storage.is_static ) && ! InitTweak::isConstExpr( mutDecl->init ) ) ) ) {
1486 // constructed objects cannot be designated
1487 if ( InitTweak::isDesignated( mutDecl->init ) ) SemanticError( mutDecl, "Cannot include designations in the initializer for a managed Object. If this is really what you want, then initialize with @=.\n" );
1488 // constructed objects should not have initializers nested too deeply
1489 if ( ! InitTweak::checkInitDepth( mutDecl ) ) SemanticError( mutDecl, "Managed object's initializer is too deep " );
1490
1491 mutDecl->init = InitTweak::genCtorInit( mutDecl->location, mutDecl );
1492 }
1493
1494 objectDecl = mutDecl;
1495 }
1496 currentObject = ast::CurrentObject{ objectDecl->location, objectDecl->get_type() };
1497 }
1498
1499 return objectDecl;
1500 }
1501
1502 void Resolver_new::previsit( const ast::AggregateDecl * _aggDecl ) {
1503 auto aggDecl = mutate(_aggDecl);
1504 assertf(aggDecl == _aggDecl, "type declarations must be unique");
1505
1506 for (auto & member: aggDecl->members) {
1507 // nested type decls are hoisted already. no need to do anything
1508 if (auto obj = member.as<ast::ObjectDecl>()) {
1509 member = fixObjectType(obj, symtab);
1510 }
1511 }
1512 }
1513
1514 void Resolver_new::previsit( const ast::StructDecl * structDecl ) {
1515 previsit(static_cast<const ast::AggregateDecl *>(structDecl));
1516 managedTypes.handleStruct(structDecl);
1517 }
1518
1519 void Resolver_new::previsit( const ast::EnumDecl * ) {
1520 // in case we decide to allow nested enums
1521 GuardValue( inEnumDecl );
1522 inEnumDecl = true;
1523 // don't need to fix types for enum fields
1524 }
1525
1526
1527 const ast::StaticAssertDecl * Resolver_new::previsit(
1528 const ast::StaticAssertDecl * assertDecl
1529 ) {
1530 return ast::mutate_field(
1531 assertDecl, &ast::StaticAssertDecl::cond,
1532 findIntegralExpression( assertDecl->cond, symtab ) );
1533 }
1534
1535 template< typename PtrType >
1536 const PtrType * handlePtrType( const PtrType * type, const ast::SymbolTable & symtab ) {
1537 if ( type->dimension ) {
1538 ast::ptr< ast::Type > sizeType = ast::sizeType;
1539 ast::mutate_field(
1540 type, &PtrType::dimension,
1541 findSingleExpression( type->dimension, sizeType, symtab ) );
1542 }
1543 return type;
1544 }
1545
1546 const ast::ArrayType * Resolver_new::previsit( const ast::ArrayType * at ) {
1547 return handlePtrType( at, symtab );
1548 }
1549
1550 const ast::PointerType * Resolver_new::previsit( const ast::PointerType * pt ) {
1551 return handlePtrType( pt, symtab );
1552 }
1553
1554 const ast::ExprStmt * Resolver_new::previsit( const ast::ExprStmt * exprStmt ) {
1555 visit_children = false;
1556 assertf( exprStmt->expr, "ExprStmt has null expression in resolver" );
1557
1558 return ast::mutate_field(
1559 exprStmt, &ast::ExprStmt::expr, findVoidExpression( exprStmt->expr, symtab ) );
1560 }
1561
1562 const ast::AsmExpr * Resolver_new::previsit( const ast::AsmExpr * asmExpr ) {
1563 visit_children = false;
1564
1565 asmExpr = ast::mutate_field(
1566 asmExpr, &ast::AsmExpr::operand, findVoidExpression( asmExpr->operand, symtab ) );
1567
1568 return asmExpr;
1569 }
1570
1571 const ast::AsmStmt * Resolver_new::previsit( const ast::AsmStmt * asmStmt ) {
1572 visitor->maybe_accept( asmStmt, &ast::AsmStmt::input );
1573 visitor->maybe_accept( asmStmt, &ast::AsmStmt::output );
1574 visit_children = false;
1575 return asmStmt;
1576 }
1577
1578 const ast::IfStmt * Resolver_new::previsit( const ast::IfStmt * ifStmt ) {
1579 return ast::mutate_field(
1580 ifStmt, &ast::IfStmt::cond, findIntegralExpression( ifStmt->cond, symtab ) );
1581 }
1582
1583 const ast::WhileStmt * Resolver_new::previsit( const ast::WhileStmt * whileStmt ) {
1584 return ast::mutate_field(
1585 whileStmt, &ast::WhileStmt::cond, findIntegralExpression( whileStmt->cond, symtab ) );
1586 }
1587
1588 const ast::ForStmt * Resolver_new::previsit( const ast::ForStmt * forStmt ) {
1589 if ( forStmt->cond ) {
1590 forStmt = ast::mutate_field(
1591 forStmt, &ast::ForStmt::cond, findIntegralExpression( forStmt->cond, symtab ) );
1592 }
1593
1594 if ( forStmt->inc ) {
1595 forStmt = ast::mutate_field(
1596 forStmt, &ast::ForStmt::inc, findVoidExpression( forStmt->inc, symtab ) );
1597 }
1598
1599 return forStmt;
1600 }
1601
1602 const ast::SwitchStmt * Resolver_new::previsit( const ast::SwitchStmt * switchStmt ) {
1603 GuardValue( currentObject );
1604 switchStmt = ast::mutate_field(
1605 switchStmt, &ast::SwitchStmt::cond,
1606 findIntegralExpression( switchStmt->cond, symtab ) );
1607 currentObject = ast::CurrentObject{ switchStmt->location, switchStmt->cond->result };
1608 return switchStmt;
1609 }
1610
1611 const ast::CaseStmt * Resolver_new::previsit( const ast::CaseStmt * caseStmt ) {
1612 if ( caseStmt->cond ) {
1613 std::deque< ast::InitAlternative > initAlts = currentObject.getOptions();
1614 assertf( initAlts.size() == 1, "SwitchStmt did not correctly resolve an integral "
1615 "expression." );
1616
1617 ast::ptr< ast::Expr > untyped =
1618 new ast::CastExpr{ caseStmt->location, caseStmt->cond, initAlts.front().type };
1619 ast::ptr< ast::Expr > newExpr = findSingleExpression( untyped, symtab );
1620
1621 // case condition cannot have a cast in C, so it must be removed here, regardless of
1622 // whether it would perform a conversion.
1623 if ( const ast::CastExpr * castExpr = newExpr.as< ast::CastExpr >() ) {
1624 swap_and_save_env( newExpr, castExpr->arg );
1625 }
1626
1627 caseStmt = ast::mutate_field( caseStmt, &ast::CaseStmt::cond, newExpr );
1628 }
1629 return caseStmt;
1630 }
1631
1632 const ast::BranchStmt * Resolver_new::previsit( const ast::BranchStmt * branchStmt ) {
1633 visit_children = false;
1634 // must resolve the argument of a computed goto
1635 if ( branchStmt->kind == ast::BranchStmt::Goto && branchStmt->computedTarget ) {
1636 // computed goto argument is void*
1637 ast::ptr< ast::Type > target = new ast::PointerType{ new ast::VoidType{} };
1638 branchStmt = ast::mutate_field(
1639 branchStmt, &ast::BranchStmt::computedTarget,
1640 findSingleExpression( branchStmt->computedTarget, target, symtab ) );
1641 }
1642 return branchStmt;
1643 }
1644
1645 const ast::ReturnStmt * Resolver_new::previsit( const ast::ReturnStmt * returnStmt ) {
1646 visit_children = false;
1647 if ( returnStmt->expr ) {
1648 returnStmt = ast::mutate_field(
1649 returnStmt, &ast::ReturnStmt::expr,
1650 findSingleExpression( returnStmt->expr, functionReturn, symtab ) );
1651 }
1652 return returnStmt;
1653 }
1654
1655 const ast::ThrowStmt * Resolver_new::previsit( const ast::ThrowStmt * throwStmt ) {
1656 visit_children = false;
1657 if ( throwStmt->expr ) {
1658 const ast::StructDecl * exceptionDecl =
1659 symtab.lookupStruct( "__cfaehm_base_exception_t" );
1660 assert( exceptionDecl );
1661 ast::ptr< ast::Type > exceptType =
1662 new ast::PointerType{ new ast::StructInstType{ exceptionDecl } };
1663 throwStmt = ast::mutate_field(
1664 throwStmt, &ast::ThrowStmt::expr,
1665 findSingleExpression( throwStmt->expr, exceptType, symtab ) );
1666 }
1667 return throwStmt;
1668 }
1669
1670 const ast::CatchStmt * Resolver_new::previsit( const ast::CatchStmt * catchStmt ) {
1671 // Until we are very sure this invarent (ifs that move between passes have thenPart)
1672 // holds, check it. This allows a check for when to decode the mangling.
1673 if ( auto ifStmt = catchStmt->body.as<ast::IfStmt>() ) {
1674 assert( ifStmt->thenPart );
1675 }
1676 // Encode the catchStmt so the condition can see the declaration.
1677 if ( catchStmt->cond ) {
1678 ast::CatchStmt * stmt = mutate( catchStmt );
1679 stmt->body = new ast::IfStmt( stmt->location, stmt->cond, nullptr, stmt->body );
1680 stmt->cond = nullptr;
1681 return stmt;
1682 }
1683 return catchStmt;
1684 }
1685
1686 const ast::CatchStmt * Resolver_new::postvisit( const ast::CatchStmt * catchStmt ) {
1687 // Decode the catchStmt so everything is stored properly.
1688 const ast::IfStmt * ifStmt = catchStmt->body.as<ast::IfStmt>();
1689 if ( nullptr != ifStmt && nullptr == ifStmt->thenPart ) {
1690 assert( ifStmt->cond );
1691 assert( ifStmt->elsePart );
1692 ast::CatchStmt * stmt = ast::mutate( catchStmt );
1693 stmt->cond = ifStmt->cond;
1694 stmt->body = ifStmt->elsePart;
1695 // ifStmt should be implicately deleted here.
1696 return stmt;
1697 }
1698 return catchStmt;
1699 }
1700
1701 const ast::WaitForStmt * Resolver_new::previsit( const ast::WaitForStmt * stmt ) {
1702 visit_children = false;
1703
1704 // Resolve all clauses first
1705 for ( unsigned i = 0; i < stmt->clauses.size(); ++i ) {
1706 const ast::WaitForStmt::Clause & clause = stmt->clauses[i];
1707
1708 ast::TypeEnvironment env;
1709 CandidateFinder funcFinder{ symtab, env };
1710
1711 // Find all candidates for a function in canonical form
1712 funcFinder.find( clause.target.func, ResolvMode::withAdjustment() );
1713
1714 if ( funcFinder.candidates.empty() ) {
1715 stringstream ss;
1716 ss << "Use of undeclared indentifier '";
1717 ss << clause.target.func.strict_as< ast::NameExpr >()->name;
1718 ss << "' in call to waitfor";
1719 SemanticError( stmt->location, ss.str() );
1720 }
1721
1722 if ( clause.target.args.empty() ) {
1723 SemanticError( stmt->location,
1724 "Waitfor clause must have at least one mutex parameter");
1725 }
1726
1727 // Find all alternatives for all arguments in canonical form
1728 std::vector< CandidateFinder > argFinders =
1729 funcFinder.findSubExprs( clause.target.args );
1730
1731 // List all combinations of arguments
1732 std::vector< CandidateList > possibilities;
1733 combos( argFinders.begin(), argFinders.end(), back_inserter( possibilities ) );
1734
1735 // For every possible function:
1736 // * try matching the arguments to the parameters, not the other way around because
1737 // more arguments than parameters
1738 CandidateList funcCandidates;
1739 std::vector< CandidateList > argsCandidates;
1740 SemanticErrorException errors;
1741 for ( CandidateRef & func : funcFinder.candidates ) {
1742 try {
1743 auto pointerType = dynamic_cast< const ast::PointerType * >(
1744 func->expr->result->stripReferences() );
1745 if ( ! pointerType ) {
1746 SemanticError( stmt->location, func->expr->result.get(),
1747 "candidate not viable: not a pointer type\n" );
1748 }
1749
1750 auto funcType = pointerType->base.as< ast::FunctionType >();
1751 if ( ! funcType ) {
1752 SemanticError( stmt->location, func->expr->result.get(),
1753 "candidate not viable: not a function type\n" );
1754 }
1755
1756 {
1757 auto param = funcType->params.begin();
1758 auto paramEnd = funcType->params.end();
1759
1760 if( ! nextMutex( param, paramEnd ) ) {
1761 SemanticError( stmt->location, funcType,
1762 "candidate function not viable: no mutex parameters\n");
1763 }
1764 }
1765
1766 CandidateRef func2{ new Candidate{ *func } };
1767 // strip reference from function
1768 func2->expr = referenceToRvalueConversion( func->expr, func2->cost );
1769
1770 // Each argument must be matched with a parameter of the current candidate
1771 for ( auto & argsList : possibilities ) {
1772 try {
1773 // Declare data structures needed for resolution
1774 ast::OpenVarSet open;
1775 ast::AssertionSet need, have;
1776 ast::TypeEnvironment resultEnv{ func->env };
1777 // Add all type variables as open so that those not used in the
1778 // parameter list are still considered open
1779 resultEnv.add( funcType->forall );
1780
1781 // load type variables from arguments into one shared space
1782 for ( auto & arg : argsList ) {
1783 resultEnv.simpleCombine( arg->env );
1784 }
1785
1786 // Make sure we don't widen any existing bindings
1787 resultEnv.forbidWidening();
1788
1789 // Find any unbound type variables
1790 resultEnv.extractOpenVars( open );
1791
1792 auto param = funcType->params.begin();
1793 auto paramEnd = funcType->params.end();
1794
1795 unsigned n_mutex_param = 0;
1796
1797 // For every argument of its set, check if it matches one of the
1798 // parameters. The order is important
1799 for ( auto & arg : argsList ) {
1800 // Ignore non-mutex arguments
1801 if ( ! nextMutex( param, paramEnd ) ) {
1802 // We ran out of parameters but still have arguments.
1803 // This function doesn't match
1804 SemanticError( stmt->location, funcType,
1805 toString("candidate function not viable: too many mutex "
1806 "arguments, expected ", n_mutex_param, "\n" ) );
1807 }
1808
1809 ++n_mutex_param;
1810
1811 // Check if the argument matches the parameter type in the current
1812 // scope
1813 // ast::ptr< ast::Type > paramType = (*param)->get_type();
1814 if (
1815 ! unify(
1816 arg->expr->result, *param, resultEnv, need, have, open,
1817 symtab )
1818 ) {
1819 // Type doesn't match
1820 stringstream ss;
1821 ss << "candidate function not viable: no known conversion "
1822 "from '";
1823 ast::print( ss, *param );
1824 ss << "' to '";
1825 ast::print( ss, arg->expr->result );
1826 ss << "' with env '";
1827 ast::print( ss, resultEnv );
1828 ss << "'\n";
1829 SemanticError( stmt->location, funcType, ss.str() );
1830 }
1831
1832 ++param;
1833 }
1834
1835 // All arguments match!
1836
1837 // Check if parameters are missing
1838 if ( nextMutex( param, paramEnd ) ) {
1839 do {
1840 ++n_mutex_param;
1841 ++param;
1842 } while ( nextMutex( param, paramEnd ) );
1843
1844 // We ran out of arguments but still have parameters left; this
1845 // function doesn't match
1846 SemanticError( stmt->location, funcType,
1847 toString( "candidate function not viable: too few mutex "
1848 "arguments, expected ", n_mutex_param, "\n" ) );
1849 }
1850
1851 // All parameters match!
1852
1853 // Finish the expressions to tie in proper environments
1854 finishExpr( func2->expr, resultEnv );
1855 for ( CandidateRef & arg : argsList ) {
1856 finishExpr( arg->expr, resultEnv );
1857 }
1858
1859 // This is a match, store it and save it for later
1860 funcCandidates.emplace_back( std::move( func2 ) );
1861 argsCandidates.emplace_back( std::move( argsList ) );
1862
1863 } catch ( SemanticErrorException & e ) {
1864 errors.append( e );
1865 }
1866 }
1867 } catch ( SemanticErrorException & e ) {
1868 errors.append( e );
1869 }
1870 }
1871
1872 // Make sure correct number of arguments
1873 if( funcCandidates.empty() ) {
1874 SemanticErrorException top( stmt->location,
1875 "No alternatives for function in call to waitfor" );
1876 top.append( errors );
1877 throw top;
1878 }
1879
1880 if( argsCandidates.empty() ) {
1881 SemanticErrorException top( stmt->location,
1882 "No alternatives for arguments in call to waitfor" );
1883 top.append( errors );
1884 throw top;
1885 }
1886
1887 if( funcCandidates.size() > 1 ) {
1888 SemanticErrorException top( stmt->location,
1889 "Ambiguous function in call to waitfor" );
1890 top.append( errors );
1891 throw top;
1892 }
1893 if( argsCandidates.size() > 1 ) {
1894 SemanticErrorException top( stmt->location,
1895 "Ambiguous arguments in call to waitfor" );
1896 top.append( errors );
1897 throw top;
1898 }
1899 // TODO: need to use findDeletedExpr to ensure no deleted identifiers are used.
1900
1901 // build new clause
1902 ast::WaitForStmt::Clause clause2;
1903
1904 clause2.target.func = funcCandidates.front()->expr;
1905
1906 clause2.target.args.reserve( clause.target.args.size() );
1907 for ( auto arg : argsCandidates.front() ) {
1908 clause2.target.args.emplace_back( std::move( arg->expr ) );
1909 }
1910
1911 // Resolve the conditions as if it were an IfStmt, statements normally
1912 clause2.cond = findSingleExpression( clause.cond, symtab );
1913 clause2.stmt = clause.stmt->accept( *visitor );
1914
1915 // set results into stmt
1916 auto n = mutate( stmt );
1917 n->clauses[i] = std::move( clause2 );
1918 stmt = n;
1919 }
1920
1921 if ( stmt->timeout.stmt ) {
1922 // resolve the timeout as a size_t, the conditions like IfStmt, and stmts normally
1923 ast::WaitForStmt::Timeout timeout2;
1924
1925 ast::ptr< ast::Type > target =
1926 new ast::BasicType{ ast::BasicType::LongLongUnsignedInt };
1927 timeout2.time = findSingleExpression( stmt->timeout.time, target, symtab );
1928 timeout2.cond = findSingleExpression( stmt->timeout.cond, symtab );
1929 timeout2.stmt = stmt->timeout.stmt->accept( *visitor );
1930
1931 // set results into stmt
1932 auto n = mutate( stmt );
1933 n->timeout = std::move( timeout2 );
1934 stmt = n;
1935 }
1936
1937 if ( stmt->orElse.stmt ) {
1938 // resolve the condition like IfStmt, stmts normally
1939 ast::WaitForStmt::OrElse orElse2;
1940
1941 orElse2.cond = findSingleExpression( stmt->orElse.cond, symtab );
1942 orElse2.stmt = stmt->orElse.stmt->accept( *visitor );
1943
1944 // set results into stmt
1945 auto n = mutate( stmt );
1946 n->orElse = std::move( orElse2 );
1947 stmt = n;
1948 }
1949
1950 return stmt;
1951 }
1952
1953 const ast::WithStmt * Resolver_new::previsit( const ast::WithStmt * withStmt ) {
1954 auto mutStmt = mutate(withStmt);
1955 resolveWithExprs(mutStmt->exprs, stmtsToAddBefore);
1956 return mutStmt;
1957 }
1958
1959 void Resolver_new::resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd) {
1960 for (auto & expr : exprs) {
1961 // only struct- and union-typed expressions are viable candidates
1962 expr = findKindExpression( expr, symtab, structOrUnion, "with expression" );
1963
1964 // if with expression might be impure, create a temporary so that it is evaluated once
1965 if ( Tuples::maybeImpure( expr ) ) {
1966 static UniqueName tmpNamer( "_with_tmp_" );
1967 const CodeLocation loc = expr->location;
1968 auto tmp = new ast::ObjectDecl(loc, tmpNamer.newName(), expr->result, new ast::SingleInit(loc, expr ) );
1969 expr = new ast::VariableExpr( loc, tmp );
1970 stmtsToAdd.push_back( new ast::DeclStmt(loc, tmp ) );
1971 if ( InitTweak::isConstructable( tmp->type ) ) {
1972 // generate ctor/dtor and resolve them
1973 tmp->init = InitTweak::genCtorInit( loc, tmp );
1974 }
1975 // since tmp is freshly created, this should modify tmp in-place
1976 tmp->accept( *visitor );
1977 }
1978 }
1979 }
1980
1981
1982 const ast::SingleInit * Resolver_new::previsit( const ast::SingleInit * singleInit ) {
1983 visit_children = false;
1984 // resolve initialization using the possibilities as determined by the `currentObject`
1985 // cursor.
1986 ast::ptr< ast::Expr > untyped = new ast::UntypedInitExpr{
1987 singleInit->location, singleInit->value, currentObject.getOptions() };
1988 ast::ptr<ast::Expr> newExpr = findSingleExpression( untyped, symtab );
1989 const ast::InitExpr * initExpr = newExpr.strict_as< ast::InitExpr >();
1990
1991 // move cursor to the object that is actually initialized
1992 currentObject.setNext( initExpr->designation );
1993
1994 // discard InitExpr wrapper and retain relevant pieces.
1995 // `initExpr` may have inferred params in the case where the expression specialized a
1996 // function pointer, and newExpr may already have inferParams of its own, so a simple
1997 // swap is not sufficient
1998 ast::Expr::InferUnion inferred = initExpr->inferred;
1999 swap_and_save_env( newExpr, initExpr->expr );
2000 newExpr.get_and_mutate()->inferred.splice( std::move(inferred) );
2001
2002 // get the actual object's type (may not exactly match what comes back from the resolver
2003 // due to conversions)
2004 const ast::Type * initContext = currentObject.getCurrentType();
2005
2006 removeExtraneousCast( newExpr, symtab );
2007
2008 // check if actual object's type is char[]
2009 if ( auto at = dynamic_cast< const ast::ArrayType * >( initContext ) ) {
2010 if ( isCharType( at->base ) ) {
2011 // check if the resolved type is char*
2012 if ( auto pt = newExpr->result.as< ast::PointerType >() ) {
2013 if ( isCharType( pt->base ) ) {
2014 // strip cast if we're initializing a char[] with a char*
2015 // e.g. char x[] = "hello"
2016 if ( auto ce = newExpr.as< ast::CastExpr >() ) {
2017 swap_and_save_env( newExpr, ce->arg );
2018 }
2019 }
2020 }
2021 }
2022 }
2023
2024 // move cursor to next object in preparation for next initializer
2025 currentObject.increment();
2026
2027 // set initializer expression to resolved expression
2028 return ast::mutate_field( singleInit, &ast::SingleInit::value, std::move(newExpr) );
2029 }
2030
2031 const ast::ListInit * Resolver_new::previsit( const ast::ListInit * listInit ) {
2032 // move cursor into brace-enclosed initializer-list
2033 currentObject.enterListInit( listInit->location );
2034
2035 assert( listInit->designations.size() == listInit->initializers.size() );
2036 for ( unsigned i = 0; i < listInit->designations.size(); ++i ) {
2037 // iterate designations and initializers in pairs, moving the cursor to the current
2038 // designated object and resolving the initializer against that object
2039 listInit = ast::mutate_field_index(
2040 listInit, &ast::ListInit::designations, i,
2041 currentObject.findNext( listInit->designations[i] ) );
2042 listInit = ast::mutate_field_index(
2043 listInit, &ast::ListInit::initializers, i,
2044 listInit->initializers[i]->accept( *visitor ) );
2045 }
2046
2047 // move cursor out of brace-enclosed initializer-list
2048 currentObject.exitListInit();
2049
2050 visit_children = false;
2051 return listInit;
2052 }
2053
2054 const ast::ConstructorInit * Resolver_new::previsit( const ast::ConstructorInit * ctorInit ) {
2055 visitor->maybe_accept( ctorInit, &ast::ConstructorInit::ctor );
2056 visitor->maybe_accept( ctorInit, &ast::ConstructorInit::dtor );
2057
2058 // found a constructor - can get rid of C-style initializer
2059 // xxx - Rob suggests this field is dead code
2060 ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::init, nullptr );
2061
2062 // intrinsic single-parameter constructors and destructors do nothing. Since this was
2063 // implicitly generated, there's no way for it to have side effects, so get rid of it to
2064 // clean up generated code
2065 if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->ctor ) ) {
2066 ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::ctor, nullptr );
2067 }
2068 if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->dtor ) ) {
2069 ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::dtor, nullptr );
2070 }
2071
2072 return ctorInit;
2073 }
2074
2075 // suppress error on autogen functions and mark invalid autogen as deleted.
2076 bool Resolver_new::on_error(ast::ptr<ast::Decl> & decl) {
2077 if (auto functionDecl = decl.as<ast::FunctionDecl>()) {
2078 // xxx - can intrinsic gen ever fail?
2079 if (functionDecl->linkage == ast::Linkage::AutoGen) {
2080 auto mutDecl = mutate(functionDecl);
2081 mutDecl->isDeleted = true;
2082 mutDecl->stmts = nullptr;
2083 decl = mutDecl;
2084 return false;
2085 }
2086 }
2087 return true;
2088 }
2089
2090} // namespace ResolvExpr
2091
2092// Local Variables: //
2093// tab-width: 4 //
2094// mode: c++ //
2095// compile-command: "make install" //
2096// End: //
Note: See TracBrowser for help on using the repository browser.