source: src/ResolvExpr/Resolver.cc@ 0fa0201d

Last change on this file since 0fa0201d was 2345ab3, checked in by Andrew Beach <ajbeach@…>, 22 months ago

Clean-up of the chain mutator. Seems like it is underused.

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