source: src/ResolvExpr/Resolver.cc@ 7329b0a

Last change on this file since 7329b0a was 7329b0a, checked in by Andrew Beach <ajbeach@…>, 22 months ago

advance_to_mutex has been replaced nextMutex.

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