source: src/ResolvExpr/Resolver.cc@ 994030ce

Last change on this file since 994030ce was 8f557161, checked in by Michael Brooks <mlbrooks@…>, 2 years ago

Clarify and fix accuracy in eval public API, on reporting "unable to evaluate."

While the eval internals always used the flag pair valid and cfavalid almost correctly, the public interface exposed the outcome as a single flag, and the various interpretations of this flag were a mess.

Old cfacc treated sizeof(whatever) in some contexts as "known to be zero," which is wrong.
The generally correct answer, which new cfacc now uses is, "unknown now, but GCC will see it as a fine constant."
New tests/eval.cfa captures this fact: is runnable and would fail on old cfacc; it passes with new cfacc.

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