source: src/ResolvExpr/Resolver.cc@ 33e4e8ef

Last change on this file since 33e4e8ef was 4a89b52, checked in by Andrew Beach <ajbeach@…>, 22 months ago

Renamed ResolvMode to ResolveMode. This is less consistent with the namespace, but is more consistent with almost everything else.

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