source: src/ResolvExpr/Resolver.cpp@ c01a2fd

Last change on this file since c01a2fd was 8315947, checked in by JiadaL <j82liang@…>, 15 months ago

Remove automatic conversion from Enum type name to its len; change With() semantic for enum to avoid type ambiguity (not fully implemented)

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