source: src/ResolvExpr/Resolver.cpp@ 718601e

Last change on this file since 718601e was 81e768d, checked in by Michael Brooks <mlbrooks@…>, 10 months ago

Fix #276; add support for c-array parameters using dependent lengths.

Without this fix, declarations like

void f( int m, int n, float[m][n] );

would either

  • generate bad C code, with unmangled variable names appearing in the function definition, or
  • refuse to resolve a valid-c call of such a function.

tests/array-collections/c-dependent: add direct tests of such cases
tests/tuplearray: activate and expand cases which were blocked on #276
tests/array: activate case fm5y, which was blocked on #276; [noise] adjust source line numbers in .expect
tests/typedefRedef: expand coverage of "error, an array detail is different" cases; [noise] adjust source line numbers in .expect
tests/functions: [noise] adjust .expect to have resolved array sizes (extra casts) in the diffed code dump

The fix is:

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